You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
895 lines
32 KiB
895 lines
32 KiB
// 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
|
|
|