-rw-r--r-- | pwmanager/pwmanager/libgcryptif.cpp | 420 | ||||
-rw-r--r-- | pwmanager/pwmanager/libgcryptif.h | 5 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmanagerE.pro | 10 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmdoc.cpp | 77 |
4 files changed, 446 insertions, 66 deletions
diff --git a/pwmanager/pwmanager/libgcryptif.cpp b/pwmanager/pwmanager/libgcryptif.cpp index 8e55144..6f3a994 100644 --- a/pwmanager/pwmanager/libgcryptif.cpp +++ b/pwmanager/pwmanager/libgcryptif.cpp @@ -435 +435,421 @@ void LibGCryptIf::unpadData(const unsigned char *buf, #endif // CONFIG_PWMANAGER_GCRY + +#ifdef CONFIG_PWMANAGER_CRYPTO + +#include "pwmdoc.h" +#include "randomizer.h" + +#include <openssl/crypto.h> + +PwMerror LibGCryptIf::encrypt(unsigned char **outBuf, + size_t *outBufLen, + unsigned char *inBuf, + size_t inBufLen, + const unsigned char *key, + size_t keylen, + char _algo) +{ + PwMerror ret = e_success; + gcry_error_t err; + gcry_cipher_hd_t handle; + size_t blklen; + size_t unpaddedLen = inBufLen; + size_t cipherKeylen; + unsigned char *hashedKey; + unsigned char salt[STRING2KEY_SALTLEN]; + int algo = mapCipherId(_algo); + + if (!inBufLen || !keylen) + return e_invalidArg; + + // test if algo is ready for encryption + err = gcry_cipher_algo_info(algo, + GCRYCTL_TEST_ALGO, + 0, 0); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doEncrypt(): GCRYCTL_TEST_ALGO failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out; + } + // get the algo block length + err = gcry_cipher_algo_info(algo, + GCRYCTL_GET_BLKLEN, + 0, + &blklen); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doEncrypt(): GCRYCTL_GET_BLKLEN failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out; + } + /* double check if we have enough space. + * We have only 1024 extra bytes for padding and salt. + */ + BUG_ON(blklen > 1024 - STRING2KEY_SALTLEN); + // get the algo key length + err = gcry_cipher_algo_info(algo, + GCRYCTL_GET_KEYLEN, + 0, + &cipherKeylen); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doEncrypt(): GCRYCTL_GET_KEYLEN failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out; + } + // now open the algo and get a handle + err = gcry_cipher_open(&handle, + algo, + GCRY_CIPHER_MODE_CBC, + 0); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doEncrypt(): gcry_cipher_open() failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out; + } + // hash the "key" to a fixed size hash matching "cipherKeylen" + hashedKey = new unsigned char[cipherKeylen]; + hashPassphrase(key, keylen, salt, hashedKey, cipherKeylen, true); + // so now set the hashed key + err = gcry_cipher_setkey(handle, hashedKey, cipherKeylen); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doEncrypt(): gcry_cipher_setkey() failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + delete [] hashedKey; + goto out_close; + } + delete [] hashedKey; + /* allocate a buffer for the encrypted data. + * The size of the buffer is the inBuf length, but blklen + * aligned and plus the length of the salt, that is appended. + */ + *outBufLen = getBufLen(unpaddedLen, blklen) + STRING2KEY_SALTLEN; + *outBuf = new unsigned char[*outBufLen]; + padData(inBuf, unpaddedLen, blklen); + // encrypt the padded data + err = gcry_cipher_encrypt(handle, + *outBuf, + *outBufLen - STRING2KEY_SALTLEN, + inBuf, + *outBufLen - STRING2KEY_SALTLEN); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doEncrypt(): gcry_cipher_encrypt() failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out_delete; + } + // append the salt to the encrypted data + memcpy(*outBuf + *outBufLen - STRING2KEY_SALTLEN, salt, STRING2KEY_SALTLEN); + goto out_close; +out_delete: + delete [] *outBuf; +out_close: + gcry_cipher_close(handle); +out: + return ret; +} + +PwMerror LibGCryptIf::decrypt(unsigned char **outBuf, + size_t *outBufLen, + const unsigned char *inBuf, + size_t inBufLen, + const unsigned char *key, + size_t keylen, + char _algo) +{ + PwMerror ret = e_success; + gcry_error_t err; + gcry_cipher_hd_t handle; + size_t cipherKeylen; + unsigned char *hashedKey; + unsigned char salt[STRING2KEY_SALTLEN]; + int algo = mapCipherId(_algo); + + if (!inBufLen || !keylen) + return e_invalidArg; + + // test if algo is ready for encryption + err = gcry_cipher_algo_info(algo, + GCRYCTL_TEST_ALGO, + 0, 0); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doDecrypt(): GCRYCTL_TEST_ALGO failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out; + } + // get algo key length + err = gcry_cipher_algo_info(algo, + GCRYCTL_GET_KEYLEN, + 0, + &cipherKeylen); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doDecrypt(): GCRYCTL_GET_KEYLEN failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out; + } + // extract the salt of the encrypted data buffer + memcpy(salt, inBuf + inBufLen - STRING2KEY_SALTLEN, STRING2KEY_SALTLEN); + // open the algo and get a handle + err = gcry_cipher_open(&handle, + algo, + GCRY_CIPHER_MODE_CBC, + 0); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doDecrypt(): gcry_cipher_open() failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out; + } + // hash the "key" to a fixed size hash matching "cipherKeylen" + hashedKey = new unsigned char[cipherKeylen]; + hashPassphrase(key, keylen, salt, hashedKey, cipherKeylen, false); + // so now set the hashed key + err = gcry_cipher_setkey(handle, hashedKey, cipherKeylen); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doDecrypt(): gcry_cipher_setkey() failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + delete [] hashedKey; + goto out_close; + } + delete [] hashedKey; + *outBufLen = inBufLen - STRING2KEY_SALTLEN; + *outBuf = new unsigned char[*outBufLen]; + // decrypt the data + err = gcry_cipher_decrypt(handle, + *outBuf, + *outBufLen, + inBuf, + *outBufLen); + if (err != GPG_ERR_NO_ERROR) { + printDebug(string("LibGCryptIf::doEncrypt(): gcry_cipher_encrypt() failed: ") + + gcry_strerror(err)); + ret = e_cryptNotImpl; + goto out_delete; + } + // remove all random padding + unpadData(*outBuf, outBufLen); + goto out_close; +out_delete: + delete [] *outBuf; +out_close: + gcry_cipher_close(handle); +out: + return ret; +} + +PwMerror LibGCryptIf::hash(unsigned char **outBuf, + size_t *outBufLen, + const unsigned char *inBuf, + size_t inBufLen, + char _algo) +{ + PwMerror ret = e_success; + unsigned int hashLen; + int algo = mapHashId(_algo); + + hashLen = gcry_md_get_algo_dlen(algo); + *outBufLen = hashLen; + *outBuf = new unsigned char[*outBufLen]; + gcry_md_hash_buffer(algo, + *outBuf, + inBuf, + inBufLen); + return ret; +} + +unsigned int LibGCryptIf::hashLength(char _algo) +{ + unsigned int ret; + int algo = mapHashId(_algo); + ret = gcry_md_get_algo_dlen(algo); + return ret; +} + +int LibGCryptIf::mapCipherId(char algo) +{ + switch (algo) { + case PWM_CRYPT_AES128: + return GCRY_CIPHER_AES; + case PWM_CRYPT_AES192: + return GCRY_CIPHER_AES192; + case PWM_CRYPT_AES256: + return GCRY_CIPHER_AES256; + case PWM_CRYPT_3DES: + return GCRY_CIPHER_3DES; + case PWM_CRYPT_TWOFISH: + return GCRY_CIPHER_TWOFISH; + case PWM_CRYPT_TWOFISH128: + return GCRY_CIPHER_TWOFISH128; + default: + BUG(); + } + return GCRY_CIPHER_NONE; +} + +int LibGCryptIf::mapHashId(char algo) +{ + switch (algo) { + case PWM_HASH_SHA1: + return GCRY_MD_SHA1; + case PWM_HASH_SHA256: + return GCRY_MD_SHA256; + case PWM_HASH_SHA384: + return GCRY_MD_SHA384; + case PWM_HASH_SHA512: + return GCRY_MD_SHA512; + case PWM_HASH_MD5: + return GCRY_MD_MD5; + case PWM_HASH_RMD160: + return GCRY_MD_RMD160; + case PWM_HASH_TIGER: + return GCRY_MD_TIGER; + default: + BUG(); + } + return GCRY_MD_NONE; +} + +bool LibGCryptIf::hashPassphrase(const unsigned char *pw, + size_t pwlen, + unsigned char *salt, + unsigned char *key, + size_t keylen, + bool create) +{ + DEK dek; + STRING2KEY s2k; + bool ret; + + dek.keylen = keylen; + s2k.mode = 1; + s2k.hash_algo = mapHashId(conf()->confGlobHashAlgo()); + s2k.count = 0; + if (!create) + memcpy(s2k.salt, salt, STRING2KEY_SALTLEN); + ret = doHashPassphrase(&dek, + pw, + pwlen, + &s2k, + create); + if (!ret) + goto out; + memcpy(key, dek.key, dek.keylen); + if (create) + memcpy(salt, s2k.salt, STRING2KEY_SALTLEN); +out: + return ret; +} + + +bool LibGCryptIf::doHashPassphrase(DEK *dek, + const unsigned char *pw, + size_t pwlen, + STRING2KEY *s2k, + bool create) +{ + // This function is derived from GnuPG-1.2.5-rc2 + gcry_md_hd_t md; + gcry_error_t err; + bool ret = true; + size_t pass, i; + size_t used = 0; + + PWM_ASSERT(s2k->hash_algo); + BUG_ON(!(dek->keylen > 0 && dek->keylen <= array_size(dek->key))); + + err = gcry_md_open(&md, s2k->hash_algo, 0); + if (err != GPG_ERR_NO_ERROR) { + ret = false; + goto out; + } + for (pass = 0; used < dek->keylen; pass++) { + if (pass) { + gcry_md_reset(md); + for (i = 0; i < pass; i++) // preset the hash context + gcry_md_putc(md, 0); + } + if (s2k->mode == 1 || s2k->mode == 3) { + size_t len2 = pwlen + 8; + size_t count = len2; + + if (create && !pass) { + Randomizer *rnd = Randomizer::obj(); + const unsigned int salt_len = 8; + string rndBuf(rnd->genRndBuf(salt_len)); + memcpy(s2k->salt, rndBuf.c_str(), salt_len); + if (s2k->mode == 3) + s2k->count = 96; // 65536 iterations + } + if (s2k->mode == 3) { + count = (16ul + (s2k->count & 15)) << ((s2k->count >> 4) + 6); + if (count < len2) + count = len2; + } + // a little bit complicated because we need a ulong for count + while (count > len2) { // maybe iterated+salted + gcry_md_write(md, s2k->salt, 8); + gcry_md_write(md, pw, pwlen); + count -= len2; + } + if (count < 8) { + gcry_md_write(md, s2k->salt, count); + } else { + gcry_md_write(md, s2k->salt, 8); + count -= 8; + gcry_md_write(md, pw, count); + } + } else + gcry_md_write(md, pw, pwlen); + gcry_md_final(md); + i = gcry_md_get_algo_dlen(s2k->hash_algo); + if (i > dek->keylen - used) + i = dek->keylen - used; + memcpy(dek->key+used, gcry_md_read(md, s2k->hash_algo), i); + used += i; + } + gcry_md_close(md); +out: + return ret; +} + +void LibGCryptIf::padData(unsigned char *buf, + size_t bufLen, + size_t boundary) +{ + size_t numPadBytes = boundary - ((bufLen + 1) % boundary); + buf[bufLen] = static_cast<char>(0x01); + size_t i = 0; + Randomizer *rnd = Randomizer::obj(); + char c; + unsigned char *b; + while (i < numPadBytes) { + c = rnd->genRndChar(); + if (c == static_cast<char>(0x01)) + continue; + b = buf + bufLen + 1 + i; + *b = c; + ++i; + } +} + +void LibGCryptIf::unpadData(const unsigned char *buf, + size_t *bufLen) +{ + size_t pos; + BUG_ON(*bufLen % 8); + pos = *bufLen - 1; + while (buf[pos] != static_cast<char>(0x01)) { + BUG_ON(!pos); + --pos; + } + *bufLen = pos; +} + +#endif // CONFIG_PWMANAGER_CRYPTO + diff --git a/pwmanager/pwmanager/libgcryptif.h b/pwmanager/pwmanager/libgcryptif.h index e86d638..7390827 100644 --- a/pwmanager/pwmanager/libgcryptif.h +++ b/pwmanager/pwmanager/libgcryptif.h @@ -20,4 +20,7 @@ +//US ENH: should we put this better into globalstuff.h? +#define CONFIG_PWMANAGER_CRYPTO + //#undef CONFIG_PWMANAGER_GCRY // for debugging only. -#ifdef CONFIG_PWMANAGER_GCRY +#if defined CONFIG_PWMANAGER_GCRY || defined CONFIG_PWMANAGER_CRYPTO diff --git a/pwmanager/pwmanager/pwmanagerE.pro b/pwmanager/pwmanager/pwmanagerE.pro index 52d7586..294f549 100644 --- a/pwmanager/pwmanager/pwmanagerE.pro +++ b/pwmanager/pwmanager/pwmanagerE.pro @@ -12,3 +12,3 @@ DEFINES += PWM_EMBEDDED #enable this setting if you want debugoutput for pwmanager -#DEFINES += CONFIG_DEBUG +DEFINES += CONFIG_DEBUG @@ -20,3 +20,3 @@ LIBS += -lqpe LIBS += -lz -LIBS += -lbz2 +#LIBS += -lbz2 LIBS += -lcrypto @@ -46,2 +46,3 @@ LIBS += $(QTOPIALIB) #subtbleditimpl.h \ +#compressbzip2.h \ @@ -55,3 +56,2 @@ commentbox.h \ compiler.h \ -compressbzip2.h \ compressgzip.h \ @@ -68,2 +68,3 @@ htmlparse.h \ ipc.h \ +libgcryptif.h \ listobjselectwnd.h \ @@ -110,2 +111,3 @@ kcmconfigs/pwmconfigwidget.h \ #subtbleditimpl.cpp \ +#compressbzip2.cpp \ @@ -118,3 +120,2 @@ blowfish.cpp \ commentbox.cpp \ -compressbzip2.cpp \ compressgzip.cpp \ @@ -130,2 +131,3 @@ htmlgen.cpp \ ipc.cpp \ +libgcryptif.cpp \ listobjselectwnd.cpp \ diff --git a/pwmanager/pwmanager/pwmdoc.cpp b/pwmanager/pwmanager/pwmdoc.cpp index 4ad392e..a5df8f0 100644 --- a/pwmanager/pwmanager/pwmdoc.cpp +++ b/pwmanager/pwmanager/pwmdoc.cpp @@ -30,5 +30,4 @@ #include "pwminit.h" -#ifndef PWM_EMBEDDED -//US #include "libgryptif.h" -#else +#include "libgcryptif.h" +#ifdef PWM_EMBEDDED #include "pwmprefs.h" @@ -61,2 +60,14 @@ + +#ifdef PWM_EMBEDDED +#ifndef Q_LONG +#define Q_LONG long +#endif + +#ifndef Q_ULONG +#define Q_ULONG unsigned long +#endif +#endif //PWM_EMBEDDED + + //TODO: reset to its normal value. @@ -354,9 +365,5 @@ PwMerror PwMDoc::saveDoc(char compress, const QString *file) } -#ifndef PWM_EMBEDDED + int _cryptAlgo = conf()->confGlobCryptAlgo(); int _hashAlgo = conf()->confGlobHashAlgo(); -#else - int _cryptAlgo = PWM_CRYPT_BLOWFISH; - int _hashAlgo = PWM_HASH_SHA1; -#endif @@ -601,3 +608,2 @@ PwMerror PwMDoc::writeFileHeader(char keyHash, char dataHash, char crypt, char c PWM_ASSERT(listView); -#ifndef PWM_EMBEDDED if (f->writeBlock(FILE_ID_HEADER, strlen(FILE_ID_HEADER)) != @@ -616,17 +622,2 @@ PwMerror PwMDoc::writeFileHeader(char keyHash, char dataHash, char crypt, char c -#else - if (f->writeBlock(FILE_ID_HEADER, strlen(FILE_ID_HEADER)) != - (long)(strlen(FILE_ID_HEADER))) { - return e_writeFile; - } - if (f->putch(PWM_FILE_VER) == -1 || - f->putch(keyHash) == -1 || - f->putch(dataHash) == -1 || - f->putch(crypt) == -1 || - f->putch(compress) == -1 || - f->putch((getDocStatFlag(DOC_STAT_USE_CHIPCARD)) ? - ((char)(0x01)) : ((char)(0x00))) == -1) { - return e_writeFile; - } -#endif // write bytes of NUL-data. These bytes are reserved for future-use. @@ -648,3 +639,2 @@ PwMerror PwMDoc::writeFileHeader(char keyHash, char dataHash, char crypt, char c } -#ifndef PWM_EMBEDDED case PWM_HASH_SHA256: @@ -678,3 +668,2 @@ PwMerror PwMDoc::writeFileHeader(char keyHash, char dataHash, char crypt, char c } -#endif default: { @@ -764,3 +753,2 @@ PwMerror PwMDoc::checkHeader(char *cryptAlgo, QString *pw, char *compress, } -#ifndef PWM_EMBEDDED case PWM_HASH_SHA256: @@ -797,3 +785,2 @@ PwMerror PwMDoc::checkHeader(char *cryptAlgo, QString *pw, char *compress, } -#endif default: { @@ -807,3 +794,2 @@ PwMerror PwMDoc::checkHeader(char *cryptAlgo, QString *pw, char *compress, break; -#ifndef PWM_EMBEDDED case PWM_HASH_SHA256: @@ -823,3 +809,2 @@ PwMerror PwMDoc::checkHeader(char *cryptAlgo, QString *pw, char *compress, } -#endif default: @@ -867,3 +852,2 @@ PwMerror PwMDoc::writeDataHash(char dataHash, string *d, QFile *f) } -#ifndef PWM_EMBEDDED case PWM_HASH_SHA256: @@ -896,3 +880,2 @@ PwMerror PwMDoc::writeDataHash(char dataHash, string *d, QFile *f) } -#endif default: { @@ -937,15 +920,7 @@ bool PwMDoc::copyFile(const QString &src, const QString &dst) char tmpBuf[tmpBuf_size]; -#ifndef PWM_EMBEDDED Q_LONG bytesRead, bytesWritten; -#else - long bytesRead, bytesWritten; -#endif + while (!srcFd.atEnd()) { -#ifndef PWM_EMBEDDED bytesRead = srcFd.readBlock(tmpBuf, static_cast<Q_ULONG>(tmpBuf_size)); -#else - bytesRead = srcFd.readBlock(tmpBuf, - (unsigned long)(tmpBuf_size)); -#endif if (bytesRead == -1) { @@ -955,9 +930,4 @@ bool PwMDoc::copyFile(const QString &src, const QString &dst) } -#ifndef PWM_EMBEDDED bytesWritten = dstFd.writeBlock(tmpBuf, static_cast<Q_ULONG>(bytesRead)); -#else - bytesWritten = dstFd.writeBlock(tmpBuf, - (unsigned long)(bytesRead)); -#endif if (bytesWritten != bytesRead) { @@ -1302,3 +1272,2 @@ PwMerror PwMDoc::encrypt(string *d, const QString *pw, QFile *f, char algo) } -#ifndef PWM_EMBEDDED case PWM_CRYPT_AES128: @@ -1328,3 +1297,2 @@ PwMerror PwMDoc::encrypt(string *d, const QString *pw, QFile *f, char algo) } -#endif default: { @@ -1335,3 +1303,2 @@ PwMerror PwMDoc::encrypt(string *d, const QString *pw, QFile *f, char algo) // write encrypted data to file -#ifndef PWM_EMBEDDED if (f->writeBlock(reinterpret_cast<const char *>(encrypted), @@ -1342,10 +1309,2 @@ PwMerror PwMDoc::encrypt(string *d, const QString *pw, QFile *f, char algo) } -#else - if (f->writeBlock((const char *)(encrypted), - (unsigned long)(encSize)) - != (long)(encSize)) { - delete_ifnot_null_array(encrypted); - return e_writeFile; - } -#endif delete_ifnot_null_array(encrypted); @@ -1390,3 +1349,2 @@ PwMerror PwMDoc::decrypt(string *d, unsigned int pos, const QString *pw, } -#ifndef PWM_EMBEDDED case PWM_CRYPT_AES128: @@ -1416,3 +1374,2 @@ PwMerror PwMDoc::decrypt(string *d, unsigned int pos, const QString *pw, } -#endif default: { @@ -1454,3 +1411,2 @@ PwMerror PwMDoc::checkDataHash(char dataHashType, const string *dataHash, } -#ifndef PWM_EMBEDDED case PWM_HASH_SHA256: @@ -1482,3 +1438,2 @@ PwMerror PwMDoc::checkDataHash(char dataHashType, const string *dataHash, } -#endif default: |