// authenc.cpp - originally written and placed in the public domain by Wei Dai #include "pch.h" #ifndef CRYPTOPP_IMPORTS #include "authenc.h" NAMESPACE_BEGIN(CryptoPP) void AuthenticatedSymmetricCipherBase::AuthenticateData(const byte *input, size_t len) { // UBsan finding with -std=c++03 using memcpy CRYPTOPP_ASSERT(input && len); if(!input || !len) return; unsigned int blockSize = AuthenticationBlockSize(); unsigned int &num = m_bufferedDataLength; byte* data = m_buffer.begin(); if (data && num) // process left over data { if (num+len >= blockSize) { std::memcpy(data+num, input, blockSize-num); AuthenticateBlocks(data, blockSize); input += (blockSize-num); len -= (blockSize-num); num = 0; // drop through and do the rest } else { std::memcpy(data+num, input, len); num += (unsigned int)len; return; } } // now process the input data in blocks of blockSize bytes and save the leftovers to m_data if (len >= blockSize) { size_t leftOver = AuthenticateBlocks(input, len); input += (len - leftOver); len = leftOver; } if (data && len) std::memcpy(data, input, len); num = (unsigned int)len; } void AuthenticatedSymmetricCipherBase::SetKey(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) { m_bufferedDataLength = 0; m_state = State_Start; this->SetKeyWithoutResync(userKey, keylength, params); m_state = State_KeySet; size_t length; const byte *iv = GetIVAndThrowIfInvalid(params, length); if (iv) Resynchronize(iv, (int)length); } void AuthenticatedSymmetricCipherBase::Resynchronize(const byte *iv, int length) { if (m_state < State_KeySet) throw BadState(AlgorithmName(), "Resynchronize", "key is set"); m_bufferedDataLength = 0; m_totalHeaderLength = m_totalMessageLength = m_totalFooterLength = 0; m_state = State_KeySet; Resync(iv, this->ThrowIfInvalidIVLength(length)); m_state = State_IVSet; } void AuthenticatedSymmetricCipherBase::Update(const byte *input, size_t length) { // Part of original authenc.cpp code. Don't remove it. if (length == 0) {return;} switch (m_state) { case State_Start: case State_KeySet: throw BadState(AlgorithmName(), "Update", "setting key and IV"); case State_IVSet: AuthenticateData(input, length); m_totalHeaderLength += length; break; case State_AuthUntransformed: case State_AuthTransformed: AuthenticateLastConfidentialBlock(); m_bufferedDataLength = 0; m_state = State_AuthFooter; // fall through case State_AuthFooter: AuthenticateData(input, length); m_totalFooterLength += length; break; default: CRYPTOPP_ASSERT(false); } } void AuthenticatedSymmetricCipherBase::ProcessData(byte *outString, const byte *inString, size_t length) { if (m_state >= State_IVSet && length > MaxMessageLength()-m_totalMessageLength) throw InvalidArgument(AlgorithmName() + ": message length exceeds maximum"); m_totalMessageLength += length; reswitch: switch (m_state) { case State_Start: case State_KeySet: throw BadState(AlgorithmName(), "ProcessData", "setting key and IV"); case State_AuthFooter: throw BadState(AlgorithmName(), "ProcessData was called after footer input has started"); case State_IVSet: AuthenticateLastHeaderBlock(); m_bufferedDataLength = 0; m_state = AuthenticationIsOnPlaintext()==IsForwardTransformation() ? State_AuthUntransformed : State_AuthTransformed; goto reswitch; case State_AuthUntransformed: AuthenticateData(inString, length); AccessSymmetricCipher().ProcessData(outString, inString, length); break; case State_AuthTransformed: AccessSymmetricCipher().ProcessData(outString, inString, length); AuthenticateData(outString, length); break; default: CRYPTOPP_ASSERT(false); } } void AuthenticatedSymmetricCipherBase::TruncatedFinal(byte *mac, size_t macSize) { // https://github.com/weidai11/cryptopp/issues/954 this->ThrowIfInvalidTruncatedSize(macSize); if (m_totalHeaderLength > MaxHeaderLength()) throw InvalidArgument(AlgorithmName() + ": header length of " + IntToString(m_totalHeaderLength) + " exceeds the maximum of " + IntToString(MaxHeaderLength())); if (m_totalFooterLength > MaxFooterLength()) { if (MaxFooterLength() == 0) throw InvalidArgument(AlgorithmName() + ": additional authenticated data (AAD) cannot be input after data to be encrypted or decrypted"); else throw InvalidArgument(AlgorithmName() + ": footer length of " + IntToString(m_totalFooterLength) + " exceeds the maximum of " + IntToString(MaxFooterLength())); } switch (m_state) { case State_Start: case State_KeySet: throw BadState(AlgorithmName(), "TruncatedFinal", "setting key and IV"); case State_IVSet: AuthenticateLastHeaderBlock(); m_bufferedDataLength = 0; // fall through case State_AuthUntransformed: case State_AuthTransformed: AuthenticateLastConfidentialBlock(); m_bufferedDataLength = 0; // fall through case State_AuthFooter: AuthenticateLastFooterBlock(mac, macSize); m_bufferedDataLength = 0; break; default: CRYPTOPP_ASSERT(false); } m_state = State_KeySet; } NAMESPACE_END #endif