www.pudn.com > AES_COM_crypto++.rar > AESPHM.CPP
// Crypto++ #include "sha.h" #include "aes.h" #include "modes.h" #include "hmac.h" #include "fltrimpl.h" // AES PHM #include "aesphm.h" // debug #include "hex.h" #include "files.h" #includeusing namespace std; NAMESPACE_BEGIN(CryptoPP) enum { MINIMUM_CIPHERTEXT_LENGTH = 46, // 18 bytes padded plaintext, 20 bytes MAC, 8 bytes IV seed IV_SEED_SIZE = 8, IV_SIZE = 16 }; void AESPHM_GenerateIvFromSeed(byte const* ivSeed, byte* iv) { SecByteBlock ivHash(32); SHA256().CalculateDigest(ivHash, ivSeed, IV_SEED_SIZE); // Assumes IV_SIZE == 16 for (unsigned int i=0; i!=16; ++i) iv[i] = ivHash[i] ^ ivHash[i+16]; } unsigned int AESPHM::Encrypt( RandomNumberGenerator& rng, ConstByteArrayParameter const& passphrase, byte* output, ConstByteArrayParameter const& input) { // Generate padding unsigned int paddingLen = (15 - (input.size() % 15)) + 3; rng.GenerateBlock(output, paddingLen); output[0] = ((output[0] ^ (output[0] << 4)) & 0xf0) | ((paddingLen - 3) & 0x0f); // Establish ciphertext segment locations byte* payload = output + paddingLen; byte* ivSeed = payload + input.size(); byte* digest = ivSeed + IV_SEED_SIZE; unsigned int outputLen = (digest + HMAC ::DIGESTSIZE) - output; // Generate IV seed, IV, and key; setup encryptor rng.GenerateBlock(ivSeed, IV_SEED_SIZE); SecByteBlock key(SHA256::DIGESTSIZE); SHA256().CalculateDigest(key.begin(), passphrase.begin(), passphrase.size()); SecByteBlock iv(IV_SIZE); AESPHM_GenerateIvFromSeed(ivSeed, iv.begin()); CFB_Mode ::Encryption encryptor(key.begin(), key.size(), iv.begin()); // Encrypt padding and payload encryptor.ProcessString(output, paddingLen); encryptor.ProcessString(payload, input.begin(), input.size()); // Calculate MAC HMAC (key.begin(), key.size()).CalculateDigest(digest, output, digest-output); // Done return outputLen; } DecodingResult AESPHM::Decrypt( ConstByteArrayParameter const& passphrase, byte* output, ConstByteArrayParameter const& input) { if (input.size() < MINIMUM_CIPHERTEXT_LENGTH) return DecodingResult(); // Establish locations of IV seed and MAC byte const* digest = input.end()- HMAC ::DIGESTSIZE; byte const* ivSeed = digest - IV_SEED_SIZE; // Generate key, verify MAC SecByteBlock key(SHA256::DIGESTSIZE); SHA256().CalculateDigest(key.begin(), passphrase.begin(), passphrase.size()); byte checkDigest[HMAC ::DIGESTSIZE]; HMAC (key.begin(), key.size()).CalculateDigest(checkDigest, input.begin(), digest-input.begin()); if (memcmp(digest, checkDigest, sizeof checkDigest) != 0) return DecodingResult(); // Generate IV, setup decryptor SecByteBlock iv(IV_SIZE); AESPHM_GenerateIvFromSeed(ivSeed, iv.begin()); CFB_Mode ::Decryption decryptor(key.begin(), key.size(), iv.begin()); // See how much padding we have byte firstPadByte = 0; decryptor.ProcessString(&firstPadByte, input.begin(), 1); unsigned int paddingLen = (firstPadByte & 0x0f) + 3; if (input.begin() + paddingLen > ivSeed) return DecodingResult(); byte const* payload = input.begin() + paddingLen; unsigned int payloadLen = ivSeed - payload; // Decrypt payload if (payloadLen) { decryptor.ProcessString(output, input.begin()+1, paddingLen-1); decryptor.ProcessString(output, payload, payloadLen); } return DecodingResult(payloadLen); } ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// void AES_PHM_GenerateIvFromSeed(byte const* pbIvSeed, byte* pbIv) { SecByteBlock sbbIvHash(SHA256::DIGESTSIZE); SHA256().CalculateDigest(sbbIvHash, pbIvSeed, IV_SEED_SIZE); // Assuming that SHA256::DIGESTSIZE == 32, IV_SIZE == 16 for (unsigned int i=0; i!=IV_SIZE; ++i) pbIv[i] = sbbIvHash[i] ^ sbbIvHash[i+16]; } void AES_PHM_AppendToBuffer( SecByteBlock& sbb, unsigned int& nTotalLen, byte const* pbData, unsigned int nDataLen) { if (nTotalLen + nDataLen > sbb.size()) sbb.Grow(2*(nTotalLen + nDataLen)); memcpy(sbb+nTotalLen, pbData, nDataLen); nTotalLen += nDataLen; } ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// AES_PHM_Encryption::AES_PHM_Encryption(RandomNumberGenerator& rng, byte const* pbKey, unsigned int nKeyLen, BufferedTransformation* pOutQueue) : Filter(pOutQueue), m_rng(rng), m_nPlaintextLen(0) { m_sbbKey.resize(SHA256::DIGESTSIZE); SHA256().CalculateDigest(m_sbbKey, pbKey, nKeyLen); } void AES_PHM_Encryption::Put(byte const* pbData, unsigned int nDataLen) { AES_PHM_AppendToBuffer(m_sbbPlaintext, m_nPlaintextLen, pbData, nDataLen); } void AES_PHM_Encryption::MessageEnd(int nPropagation) { SecByteBlock sbbPadding(18); // We want the plaintext length to be a multiple of 15 bytes unsigned int nRandomPaddingLen = 15 - (m_nPlaintextLen%15); byte byFirst = m_rng.GenerateByte(); sbbPadding[0] = ((byFirst ^ (byFirst << 4)) & 0xf0) | (nRandomPaddingLen & 0x0f); nRandomPaddingLen += 3; m_rng.GenerateBlock(sbbPadding+1, nRandomPaddingLen-1); // Generate IV seed SecByteBlock sbbIvSeed(IV_SEED_SIZE); m_rng.GenerateBlock(sbbIvSeed, IV_SEED_SIZE); // Generate IV from seed SecByteBlock sbbIv(IV_SIZE); AES_PHM_GenerateIvFromSeed(sbbIvSeed, sbbIv); // Initialize AES AESEncryption aes(m_sbbKey, SHA256::DIGESTSIZE); CFB_Mode ::Encryption encryptor(m_sbbKey, SHA256::DIGESTSIZE,sbbIv); // Encrypt encryptor.ProcessString(sbbPadding, nRandomPaddingLen); encryptor.ProcessString(m_sbbPlaintext, m_nPlaintextLen); // Calculate MAC over encrypted plaintext and IV seed SecByteBlock sbbMac(HMAC ::DIGESTSIZE); HMAC mac(m_sbbKey, SHA256::DIGESTSIZE); mac.Update(sbbPadding, nRandomPaddingLen); // encrypted mac.Update(m_sbbPlaintext, m_nPlaintextLen); // encrypted mac.Update(sbbIvSeed, IV_SEED_SIZE); // plain mac.Final(sbbMac); // Output complete ciphertext if (AttachedTransformation()) { AttachedTransformation()->Put(sbbPadding, nRandomPaddingLen); // encrypted AttachedTransformation()->Put(m_sbbPlaintext, m_nPlaintextLen); // encrypted AttachedTransformation()->Put(sbbIvSeed, IV_SEED_SIZE); // plain AttachedTransformation()->Put(sbbMac, HMAC ::DIGESTSIZE); // plain } m_sbbPlaintext.resize(0); m_nPlaintextLen = 0; Filter::MessageEnd(nPropagation); } ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// AES_PHM_Decryption::AES_PHM_Decryption( byte const* pbKey, unsigned int nKeyLen, BufferedTransformation* pOutQueue) : Filter(pOutQueue), m_nCiphertextLen(0) { m_sbbKey.resize(SHA256::DIGESTSIZE); SHA256().CalculateDigest(m_sbbKey, pbKey, nKeyLen); } void AES_PHM_Decryption::Put(byte const* pbData, unsigned int nDataLen) { AES_PHM_AppendToBuffer(m_sbbCiphertext, m_nCiphertextLen, pbData, nDataLen); } void AES_PHM_Decryption::MessageEnd(int nPropagation) { /* if (m_nCiphertextLen < MINIMUM_CIPHERTEXT_LENGTH) throw InvalidCiphertextOrKey(); */ // Make the code less cluttered by using the following values unsigned int nMacPosition = m_nCiphertextLen - HMAC ::DIGESTSIZE; unsigned int nIvSeedPosition = nMacPosition - IV_SEED_SIZE; // Verify MAC /* if (!HMAC (m_sbbKey, SHA256::DIGESTSIZE).VerifyDigest( m_sbbCiphertext + nMacPosition, m_sbbCiphertext, nMacPosition)) throw InvalidCiphertextOrKey();*/ // Generate IV from seed SecByteBlock sbbIv(IV_SIZE); AES_PHM_GenerateIvFromSeed(m_sbbCiphertext + nIvSeedPosition, sbbIv); // Initialize AES AESEncryption aes(m_sbbKey, SHA256::DIGESTSIZE); CFB_Mode ::Decryption decryptor(m_sbbKey, SHA256::DIGESTSIZE, sbbIv); // Decrypt decryptor.ProcessString(m_sbbCiphertext, nIvSeedPosition); // See how much padding we have unsigned int nRandomPaddingLen = (m_sbbCiphertext[0] & 0x0f) + 3; // Output plaintext if (AttachedTransformation()) AttachedTransformation()->Put( m_sbbCiphertext + nRandomPaddingLen, nIvSeedPosition - nRandomPaddingLen); m_sbbCiphertext.resize(0); m_nCiphertextLen = 0; Filter::MessageEnd(nPropagation); } ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// NAMESPACE_END