895 lines
32 KiB
C
895 lines
32 KiB
C
// This file was extracted from the TCG Published
|
|
// Trusted Platform Module Library
|
|
// Part 4: Supporting Routines
|
|
// Family "2.0"
|
|
// Level 00 Revision 01.16
|
|
// October 30, 2014
|
|
|
|
#include "OsslCryptoEngine.h"
|
|
//
|
|
// The following sets of defines are used to allow use of the SM4 algorithm identifier while waiting for the
|
|
// SM4 implementation code to appear.
|
|
//
|
|
typedef AES_KEY SM4_KEY;
|
|
#define SM4_set_encrypt_key AES_set_encrypt_key
|
|
#define SM4_set_decrypt_key AES_set_decrypt_key
|
|
#define SM4_decrypt AES_decrypt
|
|
#define SM4_encrypt AES_encrypt
|
|
//
|
|
//
|
|
// Utility Functions
|
|
//
|
|
// _cpri_SymStartup()
|
|
//
|
|
LIB_EXPORT BOOL
|
|
_cpri__SymStartup(
|
|
void
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__GetSymmetricBlockSize()
|
|
//
|
|
// This function returns the block size of the algorithm.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// <= 0 cipher not supported
|
|
// >0 the cipher block size in bytes
|
|
//
|
|
LIB_EXPORT INT16
|
|
_cpri__GetSymmetricBlockSize(
|
|
TPM_ALG_ID symmetricAlg, // IN: the symmetric algorithm
|
|
UINT16 keySizeInBits // IN: the key size
|
|
)
|
|
{
|
|
switch (symmetricAlg)
|
|
{
|
|
#ifdef TPM_ALG_AES
|
|
case TPM_ALG_AES:
|
|
#endif
|
|
#ifdef TPM_ALG_SM4 // Both AES and SM4 use the same block size
|
|
case TPM_ALG_SM4:
|
|
#endif
|
|
if(keySizeInBits != 0) // This is mostly to have a reference to
|
|
// keySizeInBits for the compiler
|
|
return 16;
|
|
else
|
|
return 0;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
//
|
|
//
|
|
// AES Encryption
|
|
//
|
|
// _cpri__AESEncryptCBC()
|
|
//
|
|
// This function performs AES encryption in CBC chain mode. The input dIn buffer is encrypted into dOut.
|
|
// The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to
|
|
// be a multiple of the block size.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS if success
|
|
// CRYPT_PARAMETER dInSize is not a multiple of the block size
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__AESEncryptCBC(
|
|
BYTE *dOut, // OUT:
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption.
|
|
UINT32 dInSize, // IN: data size (is required to be a multiple
|
|
// of 16 bytes)
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
AES_KEY AesKey;
|
|
BYTE *pIv;
|
|
INT32 dSize; // Need a signed version
|
|
int i;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// For CBC, the data size must be an even multiple of the
|
|
// cipher block size
|
|
if((dSize % 16) != 0)
|
|
return CRYPT_PARAMETER;
|
|
// Create AES encrypt key schedule
|
|
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// XOR the data block into the IV, encrypt the IV into the IV
|
|
// and then copy the IV to the output
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
pIv = iv;
|
|
for(i = 16; i > 0; i--)
|
|
*pIv++ ^= *dIn++;
|
|
AES_encrypt(iv, iv, &AesKey);
|
|
pIv = iv;
|
|
for(i = 16; i > 0; i--)
|
|
*dOut++ = *pIv++;
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__AESDecryptCBC()
|
|
//
|
|
// This function performs AES decryption in CBC chain mode. The input dIn buffer is decrypted into dOut.
|
|
// The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to
|
|
// be a multiple of the block size.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS if success
|
|
// CRYPT_PARAMETER dInSize is not a multiple of the block size
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__AESDecryptCBC(
|
|
BYTE *dOut, // OUT: the decrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption. The size of this
|
|
// buffer is 16 byte
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
AES_KEY AesKey;
|
|
BYTE *pIv;
|
|
int i;
|
|
BYTE tmp[16];
|
|
BYTE *pT = NULL;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// For CBC, the data size must be an even multiple of the
|
|
// cipher block size
|
|
if((dSize % 16) != 0)
|
|
return CRYPT_PARAMETER;
|
|
// Create AES key schedule
|
|
if (AES_set_decrypt_key(key, keySizeInBits, &AesKey) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// Copy the input data to a temp buffer, decrypt the buffer into the output;
|
|
// XOR in the IV, and copy the temp buffer to the IV and repeat.
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
//
|
|
pT = tmp;
|
|
for(i = 16; i> 0; i--)
|
|
*pT++ = *dIn++;
|
|
AES_decrypt(tmp, dOut, &AesKey);
|
|
pIv = iv;
|
|
pT = tmp;
|
|
for(i = 16; i> 0; i--)
|
|
{
|
|
*dOut++ ^= *pIv;
|
|
*pIv++ = *pT++;
|
|
}
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__AESEncryptCFB()
|
|
//
|
|
// This function performs AES encryption in CFB chain mode. The dOut buffer receives the values
|
|
// encrypted dIn. The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will
|
|
// be modified to contain the last encrypted block.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__AESEncryptCFB(
|
|
BYTE *dOut, // OUT: the encrypted
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption.
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
BYTE *pIv = NULL;
|
|
AES_KEY AesKey;
|
|
INT32 dSize; // Need a signed version of dInSize
|
|
int i;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// Create AES encryption key schedule
|
|
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// Encrypt the IV into the IV, XOR in the data, and copy to output
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
// Encrypt the current value of the IV
|
|
AES_encrypt(iv, iv, &AesKey);
|
|
pIv = iv;
|
|
for(i = (int)(dSize < 16) ? dSize : 16; i > 0; i--)
|
|
// XOR the data into the IV to create the cipher text
|
|
// and put into the output
|
|
*dOut++ = *pIv++ ^= *dIn++;
|
|
}
|
|
// If the inner loop (i loop) was smaller than 16, then dSize would have been
|
|
// smaller than 16 and it is now negative. If it is negative, then it indicates
|
|
// how many bytes are needed to pad out the IV for the next round.
|
|
for(; dSize < 0; dSize++)
|
|
*pIv++ = 0;
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__AESDecryptCFB()
|
|
//
|
|
// This function performs AES decrypt in CFB chain mode. The dOut buffer receives the values decrypted
|
|
// from dIn.
|
|
// The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will be modified to
|
|
// contain the last decoded block, padded with zeros
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__AESDecryptCFB(
|
|
BYTE *dOut, // OUT: the decrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption.
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
BYTE *pIv = NULL;
|
|
BYTE tmp[16];
|
|
int i;
|
|
BYTE *pT;
|
|
AES_KEY AesKey;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// Create AES encryption key schedule
|
|
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
// Encrypt the IV into the temp buffer
|
|
AES_encrypt(iv, tmp, &AesKey);
|
|
pT = tmp;
|
|
pIv = iv;
|
|
for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
|
|
// Copy the current cipher text to IV, XOR
|
|
// with the temp buffer and put into the output
|
|
*dOut++ = *pT++ ^ (*pIv++ = *dIn++);
|
|
}
|
|
// If the inner loop (i loop) was smaller than 16, then dSize
|
|
// would have been smaller than 16 and it is now negative
|
|
// If it is negative, then it indicates how may fill bytes
|
|
// are needed to pad out the IV for the next round.
|
|
for(; dSize < 0; dSize++)
|
|
*pIv++ = 0;
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__AESEncryptCTR()
|
|
//
|
|
// This function performs AES encryption/decryption in CTR chain mode. The dIn buffer is encrypted into
|
|
// dOut. The input iv buffer is assumed to have a size equal to the AES block size (16 bytes). The iv will be
|
|
// incremented by the number of blocks (full and partial) that were encrypted.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__AESEncryptCTR(
|
|
BYTE *dOut, // OUT: the encrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption.
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
BYTE tmp[16];
|
|
BYTE *pT;
|
|
AES_KEY AesKey;
|
|
int i;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// Create AES encryption schedule
|
|
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
// Encrypt the current value of the IV(counter)
|
|
AES_encrypt(iv, (BYTE *)tmp, &AesKey);
|
|
//increment the counter (counter is big-endian so start at end)
|
|
for(i = 15; i >= 0; i--)
|
|
if((iv[i] += 1) != 0)
|
|
break;
|
|
// XOR the encrypted counter value with input and put into output
|
|
pT = tmp;
|
|
for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
|
|
*dOut++ = *dIn++ ^ *pT++;
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
// _cpri__AESEncryptECB()
|
|
//
|
|
// AES encryption in ECB mode. The data buffer is modified to contain the cipher text.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__AESEncryptECB(
|
|
BYTE *dOut, // OUT: encrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: clear text buffer
|
|
)
|
|
{
|
|
AES_KEY AesKey;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// For ECB, the data size must be an even multiple of the
|
|
// cipher block size
|
|
if((dSize % 16) != 0)
|
|
return CRYPT_PARAMETER;
|
|
// Create AES encrypting key schedule
|
|
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
AES_encrypt(dIn, dOut, &AesKey);
|
|
dIn = &dIn[16];
|
|
dOut = &dOut[16];
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__AESDecryptECB()
|
|
//
|
|
// This function performs AES decryption using ECB (not recommended). The cipher text dIn is decrypted
|
|
// into dOut.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__AESDecryptECB(
|
|
BYTE *dOut, // OUT: the clear text data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: cipher text buffer
|
|
)
|
|
{
|
|
AES_KEY AesKey;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// For ECB, the data size must be an even multiple of the
|
|
// cipher block size
|
|
if((dSize % 16) != 0)
|
|
return CRYPT_PARAMETER;
|
|
// Create AES decryption key schedule
|
|
if (AES_set_decrypt_key(key, keySizeInBits, &AesKey) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
AES_decrypt(dIn, dOut, &AesKey);
|
|
dIn = &dIn[16];
|
|
dOut = &dOut[16];
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__AESEncryptOFB()
|
|
//
|
|
// This function performs AES encryption/decryption in OFB chain mode. The dIn buffer is modified to
|
|
// contain the encrypted/decrypted text.
|
|
// The input iv buffer is assumed to have a size equal to the block size (16 bytes). The returned value of iv
|
|
// will be the nth encryption of the IV, where n is the number of blocks (full or partial) in the data stream.
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__AESEncryptOFB(
|
|
BYTE *dOut, // OUT: the encrypted/decrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption. The size of this
|
|
// buffer is 16 byte
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
BYTE *pIv;
|
|
AES_KEY AesKey;
|
|
INT32 dSize;
|
|
int i;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// Create AES key schedule
|
|
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// This is written so that dIn and dOut may be the same
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
// Encrypt the current value of the "IV"
|
|
AES_encrypt(iv, iv, &AesKey);
|
|
// XOR the encrypted IV into dIn to create the cipher text (dOut)
|
|
pIv = iv;
|
|
for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
|
|
*dOut++ = (*pIv++ ^ *dIn++);
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
#ifdef TPM_ALG_SM4
|
|
//
|
|
//
|
|
// SM4 Encryption
|
|
//
|
|
// _cpri__SM4EncryptCBC()
|
|
//
|
|
// This function performs SM4 encryption in CBC chain mode. The input dIn buffer is encrypted into dOut.
|
|
// The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to
|
|
// be a multiple of the block size.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS if success
|
|
// CRYPT_PARAMETER dInSize is not a multiple of the block size
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__SM4EncryptCBC(
|
|
BYTE *dOut, // OUT:
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption.
|
|
UINT32 dInSize, // IN: data size (is required to be a multiple
|
|
// of 16 bytes)
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
SM4_KEY Sm4Key;
|
|
BYTE *pIv;
|
|
INT32 dSize; // Need a signed version
|
|
int i;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// For CBC, the data size must be an even multiple of the
|
|
// cipher block size
|
|
if((dSize % 16) != 0)
|
|
return CRYPT_PARAMETER;
|
|
// Create SM4 encrypt key schedule
|
|
if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// XOR the data block into the IV, encrypt the IV into the IV
|
|
// and then copy the IV to the output
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
pIv = iv;
|
|
for(i = 16; i > 0; i--)
|
|
*pIv++ ^= *dIn++;
|
|
SM4_encrypt(iv, iv, &Sm4Key);
|
|
pIv = iv;
|
|
for(i = 16; i > 0; i--)
|
|
*dOut++ = *pIv++;
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__SM4DecryptCBC()
|
|
//
|
|
// This function performs SM4 decryption in CBC chain mode. The input dIn buffer is decrypted into dOut.
|
|
// The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to
|
|
// be a multiple of the block size.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS if success
|
|
// CRYPT_PARAMETER dInSize is not a multiple of the block size
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__SM4DecryptCBC(
|
|
BYTE *dOut, // OUT: the decrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption. The size of this
|
|
// buffer is 16 byte
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
SM4_KEY Sm4Key;
|
|
BYTE *pIv;
|
|
int i;
|
|
BYTE tmp[16];
|
|
BYTE *pT = NULL;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// For CBC, the data size must be an even multiple of the
|
|
// cipher block size
|
|
if((dSize % 16) != 0)
|
|
return CRYPT_PARAMETER;
|
|
// Create SM4 key schedule
|
|
if (SM4_set_decrypt_key(key, keySizeInBits, &Sm4Key) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// Copy the input data to a temp buffer, decrypt the buffer into the output;
|
|
// XOR in the IV, and copy the temp buffer to the IV and repeat.
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
pT = tmp;
|
|
for(i = 16; i> 0; i--)
|
|
*pT++ = *dIn++;
|
|
SM4_decrypt(tmp, dOut, &Sm4Key);
|
|
pIv = iv;
|
|
pT = tmp;
|
|
for(i = 16; i> 0; i--)
|
|
{
|
|
*dOut++ ^= *pIv;
|
|
//
|
|
*pIv++ = *pT++;
|
|
}
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__SM4EncryptCFB()
|
|
//
|
|
// This function performs SM4 encryption in CFB chain mode. The dOut buffer receives the values
|
|
// encrypted dIn. The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will
|
|
// be modified to contain the last encrypted block.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__SM4EncryptCFB(
|
|
BYTE *dOut, // OUT: the encrypted
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption.
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
BYTE *pIv;
|
|
SM4_KEY Sm4Key;
|
|
INT32 dSize; // Need a signed version of dInSize
|
|
int i;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// Create SM4 encryption key schedule
|
|
if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// Encrypt the IV into the IV, XOR in the data, and copy to output
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
// Encrypt the current value of the IV
|
|
SM4_encrypt(iv, iv, &Sm4Key);
|
|
pIv = iv;
|
|
for(i = (int)(dSize < 16) ? dSize : 16; i > 0; i--)
|
|
// XOR the data into the IV to create the cipher text
|
|
// and put into the output
|
|
*dOut++ = *pIv++ ^= *dIn++;
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__SM4DecryptCFB()
|
|
//
|
|
// This function performs SM4 decrypt in CFB chain mode. The dOut buffer receives the values decrypted
|
|
// from dIn.
|
|
//
|
|
// The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will be modified to
|
|
// contain the last decoded block, padded with zeros
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__SM4DecryptCFB(
|
|
BYTE *dOut, // OUT: the decrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption.
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
BYTE *pIv;
|
|
BYTE tmp[16];
|
|
int i;
|
|
BYTE *pT;
|
|
SM4_KEY Sm4Key;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// Create SM4 encryption key schedule
|
|
if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
// Encrypt the IV into the temp buffer
|
|
SM4_encrypt(iv, tmp, &Sm4Key);
|
|
pT = tmp;
|
|
pIv = iv;
|
|
for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
|
|
// Copy the current cipher text to IV, XOR
|
|
// with the temp buffer and put into the output
|
|
*dOut++ = *pT++ ^ (*pIv++ = *dIn++);
|
|
}
|
|
// If the inner loop (i loop) was smaller than 16, then dSize
|
|
// would have been smaller than 16 and it is now negative
|
|
// If it is negative, then it indicates how may fill bytes
|
|
// are needed to pad out the IV for the next round.
|
|
for(; dSize < 0; dSize++)
|
|
*iv++ = 0;
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__SM4EncryptCTR()
|
|
//
|
|
// This function performs SM4 encryption/decryption in CTR chain mode. The dIn buffer is encrypted into
|
|
// dOut. The input iv buffer is assumed to have a size equal to the SM4 block size (16 bytes). The iv will be
|
|
// incremented by the number of blocks (full and partial) that were encrypted.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__SM4EncryptCTR(
|
|
BYTE *dOut, // OUT: the encrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption.
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
BYTE tmp[16];
|
|
BYTE *pT;
|
|
SM4_KEY Sm4Key;
|
|
int i;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// Create SM4 encryption schedule
|
|
if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
for(; dSize > 0; dSize--)
|
|
{
|
|
// Encrypt the current value of the IV(counter)
|
|
SM4_encrypt(iv, (BYTE *)tmp, &Sm4Key);
|
|
//increment the counter
|
|
for(i = 0; i < 16; i++)
|
|
if((iv[i] += 1) != 0)
|
|
break;
|
|
// XOR the encrypted counter value with input and put into output
|
|
pT = tmp;
|
|
for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
|
|
*dOut++ = *dIn++ ^ *pT++;
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
// _cpri__SM4EncryptECB()
|
|
//
|
|
// SM4 encryption in ECB mode. The data buffer is modified to contain the cipher text.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__SM4EncryptECB(
|
|
BYTE *dOut, // OUT: encrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: clear text buffer
|
|
)
|
|
{
|
|
SM4_KEY Sm4Key;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// For ECB, the data size must be an even multiple of the
|
|
// cipher block size
|
|
if((dSize % 16) != 0)
|
|
return CRYPT_PARAMETER;
|
|
// Create SM4 encrypting key schedule
|
|
if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
SM4_encrypt(dIn, dOut, &Sm4Key);
|
|
dIn = &dIn[16];
|
|
dOut = &dOut[16];
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__SM4DecryptECB()
|
|
//
|
|
// This function performs SM4 decryption using ECB (not recommended). The cipher text dIn is decrypted
|
|
// into dOut.
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__SM4DecryptECB(
|
|
BYTE *dOut, // OUT: the clear text data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: cipher text buffer
|
|
)
|
|
{
|
|
SM4_KEY Sm4Key;
|
|
INT32 dSize;
|
|
pAssert(dOut != NULL && key != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// For ECB, the data size must be an even multiple of the
|
|
// cipher block size
|
|
if((dSize % 16) != 0)
|
|
return CRYPT_PARAMETER;
|
|
// Create SM4 decryption key schedule
|
|
if (SM4_set_decrypt_key(key, keySizeInBits, &Sm4Key) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
SM4_decrypt(dIn, dOut, &Sm4Key);
|
|
dIn = &dIn[16];
|
|
dOut = &dOut[16];
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// _cpri__SM4EncryptOFB()
|
|
//
|
|
// This function performs SM4 encryption/decryption in OFB chain mode. The dIn buffer is modified to
|
|
// contain the encrypted/decrypted text.
|
|
// The input iv buffer is assumed to have a size equal to the block size (16 bytes). The returned value of iv
|
|
// will be the nth encryption of the IV, where n is the number of blocks (full or partial) in the data stream.
|
|
//
|
|
// Return Value Meaning
|
|
//
|
|
// CRYPT_SUCCESS no non-fatal errors
|
|
//
|
|
LIB_EXPORT CRYPT_RESULT
|
|
_cpri__SM4EncryptOFB(
|
|
BYTE *dOut, // OUT: the encrypted/decrypted data
|
|
UINT32 keySizeInBits, // IN: key size in bit
|
|
BYTE *key, // IN: key buffer. The size of this buffer in
|
|
// bytes is (keySizeInBits + 7) / 8
|
|
BYTE *iv, // IN/OUT: IV for decryption. The size of this
|
|
// buffer is 16 byte
|
|
UINT32 dInSize, // IN: data size
|
|
BYTE *dIn // IN: data buffer
|
|
)
|
|
{
|
|
BYTE *pIv;
|
|
SM4_KEY Sm4Key;
|
|
INT32 dSize;
|
|
int i;
|
|
pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
|
|
if(dInSize == 0)
|
|
return CRYPT_SUCCESS;
|
|
pAssert(dInSize <= INT32_MAX);
|
|
dSize = (INT32)dInSize;
|
|
// Create SM4 key schedule
|
|
if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
|
|
FAIL(FATAL_ERROR_INTERNAL);
|
|
// This is written so that dIn and dOut may be the same
|
|
for(; dSize > 0; dSize -= 16)
|
|
{
|
|
// Encrypt the current value of the "IV"
|
|
SM4_encrypt(iv, iv, &Sm4Key);
|
|
// XOR the encrypted IV into dIn to create the cipher text (dOut)
|
|
pIv = iv;
|
|
for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
|
|
*dOut++ = (*pIv++ ^ *dIn++);
|
|
}
|
|
return CRYPT_SUCCESS;
|
|
}
|
|
#endif //% TPM_ALG_SM4
|