Path: blob/a-new-beginning/SharedDependencies/Sources/cryptopp/chachapoly.cpp
2 views
// chachapoly.cpp - written and placed in the public domain by Jeffrey Walton1// RFC 8439, Section 2.8, AEAD Construction, http://tools.ietf.org/html/rfc843923#include "pch.h"4#include "chachapoly.h"5#include "algparam.h"6#include "misc.h"78#if CRYPTOPP_MSC_VERSION9# pragma warning(disable: 4244)10#endif1112NAMESPACE_BEGIN(CryptoPP)1314////////////////////////////// IETF ChaChaTLS //////////////////////////////1516// RekeyCipherAndMac is heavier-weight than we like. The Authenc framework was17// predicated on BlockCiphers, where the key and key schedule could be18// calculated independent of the IV being used. However, the ChaCha and19// ChaCha20Poly1305 construction combines key setup and IV. That is, both are20// needed to key or rekey the cipher. Even a simple Resync() requires us to21// regenerate the initial state for both ChaCha20 and Poly1305.22void ChaCha20Poly1305_Base::RekeyCipherAndMac(const byte *userKey, size_t keylength, const NameValuePairs ¶ms)23{24// Derive MAC key25AlgorithmParameters block0 = MakeParameters("InitialBlock", (word64)0, true);26AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block0));2728// Only the first 256-bits are used to key the MAC29SecByteBlock derived(NULLPTR, 32);30AccessSymmetricCipher().ProcessString(derived, derived.size());3132// Key the Poly1305 MAC33AccessMAC().SetKey(derived, derived.size(), params);3435// Key the ChaCha20 cipher36AlgorithmParameters block1 = MakeParameters("InitialBlock", (word64)1, true);37AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block1));38}3940void ChaCha20Poly1305_Base::SetKeyWithoutResync(const byte *userKey, size_t userKeyLength, const NameValuePairs ¶ms)41{42CRYPTOPP_ASSERT(userKey && userKeyLength == 32);43m_userKey.Assign(userKey, userKeyLength);4445// ChaCha/Poly1305 initial state depends on both the key and IV. The46// IV may or may not be present during the call to SetKeyWithoutResync.47// If the IV is present, the framework will call SetKeyWithoutResync48// followed by Resynchronize which calls Resync. In this case we defer49// calculating the initial state until the call to Resynchronize.50// If the IV is not present, it avoids calling ChaCha's SetKey without51// an IV, which results in an exception. In this case the user will need52// to call Resynchronize to key ChaCha and Poly1305.53// RekeyCipherAndMac(userKey, userKeyLength, params);54CRYPTOPP_UNUSED(params);55}5657void ChaCha20Poly1305_Base::Resync(const byte *iv, size_t len)58{59CRYPTOPP_ASSERT(iv && len == 12);60RekeyCipherAndMac(m_userKey, m_userKey.SizeInBytes(),61MakeParameters(Name::IV(), ConstByteArrayParameter(iv,len)));62}6364size_t ChaCha20Poly1305_Base::AuthenticateBlocks(const byte *data, size_t len)65{66AccessMAC().Update(data, len);67return 0;68}6970void ChaCha20Poly1305_Base::AuthenticateLastHeaderBlock()71{72// Pad to a multiple of 16 or 073const byte zero[16] = {0};74size_t pad = (16U - (m_totalHeaderLength % 16)) % 16;75AccessMAC().Update(zero, pad);76}7778void ChaCha20Poly1305_Base::AuthenticateLastConfidentialBlock()79{80// Pad to a multiple of 16 or 081const byte zero[16] = {0};82size_t pad = (16U - (m_totalMessageLength % 16)) % 16;83AccessMAC().Update(zero, pad);84}8586void ChaCha20Poly1305_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize)87{88CRYPTOPP_ALIGN_DATA(8) byte length[2*sizeof(word64)];89PutWord(true, LITTLE_ENDIAN_ORDER, length+0, m_totalHeaderLength);90PutWord(true, LITTLE_ENDIAN_ORDER, length+8, m_totalMessageLength);91AccessMAC().Update(length, sizeof(length));92AccessMAC().TruncatedFinal(mac, macSize);93m_state = State_KeySet;94}9596void ChaCha20Poly1305_Base::EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength)97{98Resynchronize(iv, ivLength);99Update(aad, aadLength);100ProcessString(ciphertext, message, messageLength);101TruncatedFinal(mac, macSize);102}103104bool ChaCha20Poly1305_Base::DecryptAndVerify(byte *message, const byte *mac, size_t macLength, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength)105{106Resynchronize(iv, ivLength);107Update(aad, aadLength);108ProcessString(message, ciphertext, ciphertextLength);109return TruncatedVerify(mac, macLength);110}111112////////////////////////////// IETF XChaCha20 draft //////////////////////////////113114// RekeyCipherAndMac is heavier-weight than we like. The Authenc framework was115// predicated on BlockCiphers, where the key and key schedule could be116// calculated independent of the IV being used. However, the ChaCha and117// ChaCha20Poly1305 construction combines key setup and IV. That is, both are118// needed to key or rekey the cipher. Even a simple Resync() requires us to119// regenerate the initial state for both ChaCha20 and Poly1305.120void XChaCha20Poly1305_Base::RekeyCipherAndMac(const byte *userKey, size_t keylength, const NameValuePairs ¶ms)121{122// Derive MAC key123AlgorithmParameters block0 = MakeParameters("InitialBlock", (word64)0, true);124AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block0));125126// Only the first 256-bits are used to key the MAC127SecByteBlock derived(NULLPTR, 32);128AccessSymmetricCipher().ProcessString(derived, derived.size());129130// Key the Poly1305 MAC131AccessMAC().SetKey(derived, derived.size(), params);132133// Key the ChaCha20 cipher134AlgorithmParameters block1 = MakeParameters("InitialBlock", (word64)1, true);135AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block1));136}137138void XChaCha20Poly1305_Base::SetKeyWithoutResync(const byte *userKey, size_t userKeyLength, const NameValuePairs ¶ms)139{140CRYPTOPP_ASSERT(userKey && userKeyLength == 32);141m_userKey.Assign(userKey, userKeyLength);142143// XChaCha20/Poly1305 initial state depends on both the key and IV. The144// IV may or may not be present during the call to SetKeyWithoutResync.145// If the IV is present, the framework will call SetKeyWithoutResync146// followed by Resynchronize which calls Resync. In this case we defer147// calculating the initial state until the call to Resynchronize.148// If the IV is not present, it avoids calling ChaCha's SetKey without149// an IV, which results in an exception. In this case the user will need150// to call Resynchronize to key ChaCha and Poly1305.151// RekeyCipherAndMac(userKey, userKeyLength, params);152CRYPTOPP_UNUSED(params);153}154155void XChaCha20Poly1305_Base::Resync(const byte *iv, size_t len)156{157CRYPTOPP_ASSERT(iv && len == 24);158RekeyCipherAndMac(m_userKey, m_userKey.SizeInBytes(),159MakeParameters(Name::IV(), ConstByteArrayParameter(iv,len)));160}161162size_t XChaCha20Poly1305_Base::AuthenticateBlocks(const byte *data, size_t len)163{164AccessMAC().Update(data, len);165return 0;166}167168void XChaCha20Poly1305_Base::AuthenticateLastHeaderBlock()169{170// Pad to a multiple of 16 or 0171const byte zero[16] = {0};172size_t pad = (16 - (m_totalHeaderLength % 16)) % 16;173AccessMAC().Update(zero, pad);174}175176void XChaCha20Poly1305_Base::AuthenticateLastConfidentialBlock()177{178// Pad to a multiple of 16 or 0179const byte zero[16] = {0};180size_t pad = (16 - (m_totalMessageLength % 16)) % 16;181AccessMAC().Update(zero, pad);182}183184void XChaCha20Poly1305_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize)185{186CRYPTOPP_ALIGN_DATA(8) byte length[2*sizeof(word64)];187PutWord(true, LITTLE_ENDIAN_ORDER, length+0, m_totalHeaderLength);188PutWord(true, LITTLE_ENDIAN_ORDER, length+8, m_totalMessageLength);189AccessMAC().Update(length, sizeof(length));190AccessMAC().TruncatedFinal(mac, macSize);191m_state = State_KeySet;192}193194void XChaCha20Poly1305_Base::EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength)195{196Resynchronize(iv, ivLength);197Update(aad, aadLength);198ProcessString(ciphertext, message, messageLength);199TruncatedFinal(mac, macSize);200}201202bool XChaCha20Poly1305_Base::DecryptAndVerify(byte *message, const byte *mac, size_t macLength, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength)203{204Resynchronize(iv, ivLength);205Update(aad, aadLength);206ProcessString(message, ciphertext, ciphertextLength);207return TruncatedVerify(mac, macLength);208}209210NAMESPACE_END211212213