// 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