1// This file was extracted from the TCG Published
2// Trusted Platform Module Library
3// Part 4: Supporting Routines
4// Family "2.0"
5// Level 00 Revision 01.16
6// October 30, 2014
7
8#include       "OsslCryptoEngine.h"
9//
10//     The following sets of defines are used to allow use of the SM4 algorithm identifier while waiting for the
11//     SM4 implementation code to appear.
12//
13typedef   AES_KEY SM4_KEY;
14#define   SM4_set_encrypt_key            AES_set_encrypt_key
15#define   SM4_set_decrypt_key            AES_set_decrypt_key
16#define   SM4_decrypt                    AES_decrypt
17#define   SM4_encrypt                    AES_encrypt
18//
19//
20//      Utility Functions
21//
22//      _cpri_SymStartup()
23//
24LIB_EXPORT BOOL
25_cpri__SymStartup(
26      void
27)
28{
29      return TRUE;
30}
31//
32//
33//      _cpri__GetSymmetricBlockSize()
34//
35//     This function returns the block size of the algorithm.
36//
37//     Return Value                      Meaning
38//
39//     <= 0                              cipher not supported
40//     >0                                the cipher block size in bytes
41//
42LIB_EXPORT INT16
43_cpri__GetSymmetricBlockSize(
44      TPM_ALG_ID         symmetricAlg,        // IN: the symmetric algorithm
45      UINT16             keySizeInBits        // IN: the key size
46      )
47{
48   switch (symmetricAlg)
49   {
50#ifdef TPM_ALG_AES
51   case TPM_ALG_AES:
52#endif
53#ifdef TPM_ALG_SM4 // Both AES and SM4 use the same block size
54   case TPM_ALG_SM4:
55#endif
56       if(keySizeInBits != 0) // This is mostly to have a reference to
57              // keySizeInBits for the compiler
58              return 16;
59         else
60             return 0;
61         break;
62    default:
63        return 0;
64    }
65}
66//
67//
68//      AES Encryption
69//
70//      _cpri__AESEncryptCBC()
71//
72//     This function performs AES encryption in CBC chain mode. The input dIn buffer is encrypted into dOut.
73//     The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to
74//     be a multiple of the block size.
75//
76//     Return Value                      Meaning
77//
78//     CRYPT_SUCCESS                     if success
79//     CRYPT_PARAMETER                   dInSize is not a multiple of the block size
80//
81LIB_EXPORT CRYPT_RESULT
82_cpri__AESEncryptCBC(
83    BYTE                *dOut,          // OUT:
84    UINT32               keySizeInBits, // IN: key size in bit
85    BYTE                *key,           // IN: key buffer. The size of this buffer in
86                                        //      bytes is (keySizeInBits + 7) / 8
87    BYTE                *iv,            // IN/OUT: IV for decryption.
88    UINT32               dInSize,       // IN: data size (is required to be a multiple
89                                        //      of 16 bytes)
90    BYTE                *dIn            // IN: data buffer
91    )
92{
93    AES_KEY         AesKey;
94    BYTE           *pIv;
95    INT32           dSize;              // Need a signed version
96    int             i;
97    pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
98    if(dInSize == 0)
99        return CRYPT_SUCCESS;
100    pAssert(dInSize <= INT32_MAX);
101    dSize = (INT32)dInSize;
102    // For CBC, the data size must be an even multiple of the
103    // cipher block size
104    if((dSize % 16) != 0)
105        return CRYPT_PARAMETER;
106    // Create AES encrypt key schedule
107    if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
108        FAIL(FATAL_ERROR_INTERNAL);
109    // XOR the data block into the IV, encrypt the IV into the IV
110    // and then copy the IV to the output
111    for(; dSize > 0; dSize -= 16)
112    {
113         pIv = iv;
114         for(i = 16; i > 0; i--)
115             *pIv++ ^= *dIn++;
116         AES_encrypt(iv, iv, &AesKey);
117         pIv = iv;
118         for(i = 16; i > 0; i--)
119             *dOut++ = *pIv++;
120    }
121    return CRYPT_SUCCESS;
122}
123//
124//
125//       _cpri__AESDecryptCBC()
126//
127//      This function performs AES decryption in CBC chain mode. The input dIn buffer is decrypted into dOut.
128//      The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to
129//      be a multiple of the block size.
130//
131//      Return Value                     Meaning
132//
133//      CRYPT_SUCCESS                    if success
134//      CRYPT_PARAMETER                  dInSize is not a multiple of the block size
135//
136LIB_EXPORT CRYPT_RESULT
137_cpri__AESDecryptCBC(
138    BYTE                *dOut,          // OUT: the decrypted data
139    UINT32               keySizeInBits, // IN: key size in bit
140    BYTE                *key,           // IN: key buffer. The size of this buffer in
141                                        //     bytes is (keySizeInBits + 7) / 8
142    BYTE                *iv,            // IN/OUT: IV for decryption. The size of this
143                                        //     buffer is 16 byte
144    UINT32               dInSize,       // IN: data size
145    BYTE                *dIn            // IN: data buffer
146    )
147{
148    AES_KEY         AesKey;
149    BYTE           *pIv;
150    int             i;
151    BYTE            tmp[16];
152    BYTE           *pT = NULL;
153    INT32           dSize;
154    pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
155    if(dInSize == 0)
156        return CRYPT_SUCCESS;
157    pAssert(dInSize <= INT32_MAX);
158    dSize = (INT32)dInSize;
159    // For CBC, the data size must be an even multiple of the
160    // cipher block size
161    if((dSize % 16) != 0)
162        return CRYPT_PARAMETER;
163    // Create AES key schedule
164    if (AES_set_decrypt_key(key, keySizeInBits, &AesKey) != 0)
165        FAIL(FATAL_ERROR_INTERNAL);
166    // Copy the input data to a temp buffer, decrypt the buffer into the output;
167    // XOR in the IV, and copy the temp buffer to the IV and repeat.
168    for(; dSize > 0; dSize -= 16)
169    {
170//
171        pT = tmp;
172        for(i = 16; i> 0; i--)
173            *pT++ = *dIn++;
174        AES_decrypt(tmp, dOut, &AesKey);
175        pIv = iv;
176        pT = tmp;
177        for(i = 16; i> 0; i--)
178        {
179            *dOut++ ^= *pIv;
180            *pIv++ = *pT++;
181        }
182   }
183   return CRYPT_SUCCESS;
184}
185//
186//
187//       _cpri__AESEncryptCFB()
188//
189//      This function performs AES encryption in CFB chain mode. The dOut buffer receives the values
190//      encrypted dIn. The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will
191//      be modified to contain the last encrypted block.
192//
193//      Return Value                      Meaning
194//
195//      CRYPT_SUCCESS                     no non-fatal errors
196//
197LIB_EXPORT CRYPT_RESULT
198_cpri__AESEncryptCFB(
199   BYTE                *dOut,          // OUT: the encrypted
200   UINT32               keySizeInBits, // IN: key size in bit
201   BYTE                *key,           // IN: key buffer. The size of this buffer in
202                                       //     bytes is (keySizeInBits + 7) / 8
203   BYTE                *iv,            // IN/OUT: IV for decryption.
204   UINT32               dInSize,       // IN: data size
205   BYTE                *dIn            // IN: data buffer
206   )
207{
208   BYTE           *pIv = NULL;
209   AES_KEY         AesKey;
210   INT32           dSize;               // Need a signed version of dInSize
211   int             i;
212   pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
213   if(dInSize == 0)
214       return CRYPT_SUCCESS;
215   pAssert(dInSize <= INT32_MAX);
216   dSize = (INT32)dInSize;
217   // Create AES encryption key schedule
218   if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
219       FAIL(FATAL_ERROR_INTERNAL);
220   // Encrypt the IV into the IV, XOR in the data, and copy to output
221   for(; dSize > 0; dSize -= 16)
222   {
223       // Encrypt the current value of the IV
224       AES_encrypt(iv, iv, &AesKey);
225       pIv = iv;
226       for(i = (int)(dSize < 16) ? dSize : 16; i > 0; i--)
227           // XOR the data into the IV to create the cipher text
228           // and put into the output
229           *dOut++ = *pIv++ ^= *dIn++;
230   }
231   // If the inner loop (i loop) was smaller than 16, then dSize would have been
232   // smaller than 16 and it is now negative. If it is negative, then it indicates
233   // how many bytes are needed to pad out the IV for the next round.
234   for(; dSize < 0; dSize++)
235       *pIv++ = 0;
236   return CRYPT_SUCCESS;
237}
238//
239//
240//       _cpri__AESDecryptCFB()
241//
242//      This function performs AES decrypt in CFB chain mode. The dOut buffer receives the values decrypted
243//      from dIn.
244//      The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will be modified to
245//      contain the last decoded block, padded with zeros
246//
247//      Return Value                    Meaning
248//
249//      CRYPT_SUCCESS                   no non-fatal errors
250//
251LIB_EXPORT CRYPT_RESULT
252_cpri__AESDecryptCFB(
253   BYTE                *dOut,          // OUT: the decrypted data
254   UINT32               keySizeInBits, // IN: key size in bit
255   BYTE                *key,           // IN: key buffer. The size of this buffer in
256                                       //     bytes is (keySizeInBits + 7) / 8
257   BYTE                *iv,            // IN/OUT: IV for decryption.
258   UINT32               dInSize,       // IN: data size
259   BYTE                *dIn            // IN: data buffer
260   )
261{
262   BYTE           *pIv = NULL;
263   BYTE            tmp[16];
264   int             i;
265   BYTE           *pT;
266   AES_KEY         AesKey;
267   INT32           dSize;
268   pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
269   if(dInSize == 0)
270       return CRYPT_SUCCESS;
271   pAssert(dInSize <= INT32_MAX);
272   dSize = (INT32)dInSize;
273   // Create AES encryption key schedule
274   if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
275       FAIL(FATAL_ERROR_INTERNAL);
276   for(; dSize > 0; dSize -= 16)
277   {
278       // Encrypt the IV into the temp buffer
279       AES_encrypt(iv, tmp, &AesKey);
280       pT = tmp;
281       pIv = iv;
282       for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
283           // Copy the current cipher text to IV, XOR
284           // with the temp buffer and put into the output
285           *dOut++ = *pT++ ^ (*pIv++ = *dIn++);
286   }
287   // If the inner loop (i loop) was smaller than 16, then dSize
288   // would have been smaller than 16 and it is now negative
289   // If it is negative, then it indicates how may fill bytes
290   // are needed to pad out the IV for the next round.
291   for(; dSize < 0; dSize++)
292       *pIv++ = 0;
293   return CRYPT_SUCCESS;
294}
295//
296//
297//       _cpri__AESEncryptCTR()
298//
299//      This function performs AES encryption/decryption in CTR chain mode. The dIn buffer is encrypted into
300//      dOut. The input iv buffer is assumed to have a size equal to the AES block size (16 bytes). The iv will be
301//      incremented by the number of blocks (full and partial) that were encrypted.
302//
303//      Return Value                      Meaning
304//
305//      CRYPT_SUCCESS                     no non-fatal errors
306//
307LIB_EXPORT CRYPT_RESULT
308_cpri__AESEncryptCTR(
309   BYTE                *dOut,          // OUT: the encrypted data
310   UINT32               keySizeInBits, // IN: key size in bit
311   BYTE                *key,           // IN: key buffer. The size of this buffer in
312                                       //     bytes is (keySizeInBits + 7) / 8
313   BYTE                *iv,            // IN/OUT: IV for decryption.
314   UINT32               dInSize,       // IN: data size
315   BYTE                *dIn            // IN: data buffer
316   )
317{
318   BYTE            tmp[16];
319   BYTE           *pT;
320   AES_KEY         AesKey;
321   int             i;
322   INT32           dSize;
323   pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
324   if(dInSize == 0)
325       return CRYPT_SUCCESS;
326   pAssert(dInSize <= INT32_MAX);
327   dSize = (INT32)dInSize;
328   // Create AES encryption schedule
329   if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
330       FAIL(FATAL_ERROR_INTERNAL);
331   for(; dSize > 0; dSize -= 16)
332   {
333       // Encrypt the current value of the IV(counter)
334       AES_encrypt(iv, (BYTE *)tmp, &AesKey);
335        //increment the counter (counter is big-endian so start at end)
336        for(i = 15; i >= 0; i--)
337            if((iv[i] += 1) != 0)
338                break;
339        // XOR the encrypted counter value with input and put into output
340        pT = tmp;
341        for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
342            *dOut++ = *dIn++ ^ *pT++;
343   }
344   return CRYPT_SUCCESS;
345}
346//
347//       _cpri__AESEncryptECB()
348//
349//      AES encryption in ECB mode. The data buffer is modified to contain the cipher text.
350//
351//      Return Value                      Meaning
352//
353//      CRYPT_SUCCESS                     no non-fatal errors
354//
355LIB_EXPORT CRYPT_RESULT
356_cpri__AESEncryptECB(
357    BYTE                *dOut,          // OUT: encrypted data
358    UINT32               keySizeInBits, // IN: key size in bit
359    BYTE                *key,           // IN: key buffer. The size of this buffer in
360                                        //     bytes is (keySizeInBits + 7) / 8
361    UINT32               dInSize,       // IN: data size
362    BYTE                *dIn            // IN: clear text buffer
363    )
364{
365    AES_KEY          AesKey;
366    INT32            dSize;
367    pAssert(dOut != NULL && key != NULL && dIn != NULL);
368    if(dInSize == 0)
369        return CRYPT_SUCCESS;
370    pAssert(dInSize <= INT32_MAX);
371    dSize = (INT32)dInSize;
372    // For ECB, the data size must be an even multiple of the
373    // cipher block size
374    if((dSize % 16) != 0)
375        return CRYPT_PARAMETER;
376    // Create AES encrypting key schedule
377    if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
378        FAIL(FATAL_ERROR_INTERNAL);
379    for(; dSize > 0; dSize -= 16)
380    {
381        AES_encrypt(dIn, dOut, &AesKey);
382        dIn = &dIn[16];
383        dOut = &dOut[16];
384    }
385   return CRYPT_SUCCESS;
386}
387//
388//
389//       _cpri__AESDecryptECB()
390//
391//      This function performs AES decryption using ECB (not recommended). The cipher text dIn is decrypted
392//      into dOut.
393//
394//      Return Value                      Meaning
395//
396//      CRYPT_SUCCESS                     no non-fatal errors
397//
398LIB_EXPORT CRYPT_RESULT
399_cpri__AESDecryptECB(
400   BYTE                *dOut,          // OUT: the clear text data
401   UINT32               keySizeInBits, // IN: key size in bit
402   BYTE                *key,           // IN: key buffer. The size of this buffer in
403                                       //     bytes is (keySizeInBits + 7) / 8
404   UINT32               dInSize,       // IN: data size
405   BYTE                *dIn            // IN: cipher text buffer
406   )
407{
408   AES_KEY         AesKey;
409   INT32           dSize;
410   pAssert(dOut != NULL && key != NULL && dIn != NULL);
411   if(dInSize == 0)
412       return CRYPT_SUCCESS;
413   pAssert(dInSize <= INT32_MAX);
414   dSize = (INT32)dInSize;
415   // For ECB, the data size must be an even multiple of the
416   // cipher block size
417   if((dSize % 16) != 0)
418       return CRYPT_PARAMETER;
419   // Create AES decryption key schedule
420   if (AES_set_decrypt_key(key, keySizeInBits, &AesKey) != 0)
421       FAIL(FATAL_ERROR_INTERNAL);
422   for(; dSize > 0; dSize -= 16)
423   {
424       AES_decrypt(dIn, dOut, &AesKey);
425       dIn = &dIn[16];
426       dOut = &dOut[16];
427   }
428   return CRYPT_SUCCESS;
429}
430//
431//
432//       _cpri__AESEncryptOFB()
433//
434//      This function performs AES encryption/decryption in OFB chain mode. The dIn buffer is modified to
435//      contain the encrypted/decrypted text.
436//      The input iv buffer is assumed to have a size equal to the block size (16 bytes). The returned value of iv
437//      will be the nth encryption of the IV, where n is the number of blocks (full or partial) in the data stream.
438//
439//
440//
441//
442//      Return Value                  Meaning
443//
444//      CRYPT_SUCCESS                 no non-fatal errors
445//
446LIB_EXPORT CRYPT_RESULT
447_cpri__AESEncryptOFB(
448   BYTE               *dOut,          // OUT: the encrypted/decrypted data
449   UINT32              keySizeInBits, // IN: key size in bit
450   BYTE               *key,           // IN: key buffer. The size of this buffer in
451                                      //     bytes is (keySizeInBits + 7) / 8
452   BYTE               *iv,            // IN/OUT: IV for decryption. The size of this
453                                      //     buffer is 16 byte
454   UINT32              dInSize,       // IN: data size
455   BYTE               *dIn            // IN: data buffer
456   )
457{
458   BYTE           *pIv;
459   AES_KEY         AesKey;
460   INT32           dSize;
461   int             i;
462   pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
463   if(dInSize == 0)
464       return CRYPT_SUCCESS;
465   pAssert(dInSize <= INT32_MAX);
466   dSize = (INT32)dInSize;
467   // Create AES key schedule
468   if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
469       FAIL(FATAL_ERROR_INTERNAL);
470   // This is written so that dIn and dOut may be the same
471   for(; dSize > 0; dSize -= 16)
472   {
473       // Encrypt the current value of the "IV"
474       AES_encrypt(iv, iv, &AesKey);
475        // XOR the encrypted IV into dIn to create the cipher text (dOut)
476        pIv = iv;
477        for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
478            *dOut++ = (*pIv++ ^ *dIn++);
479   }
480   return CRYPT_SUCCESS;
481}
482#ifdef    TPM_ALG_SM4
483//
484//
485//       SM4 Encryption
486//
487//       _cpri__SM4EncryptCBC()
488//
489//      This function performs SM4 encryption in CBC chain mode. The input dIn buffer is encrypted into dOut.
490//      The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to
491//      be a multiple of the block size.
492//
493//      Return Value                      Meaning
494//
495//      CRYPT_SUCCESS                     if success
496//      CRYPT_PARAMETER                   dInSize is not a multiple of the block size
497//
498LIB_EXPORT CRYPT_RESULT
499_cpri__SM4EncryptCBC(
500    BYTE                *dOut,          // OUT:
501    UINT32               keySizeInBits, // IN: key size in bit
502    BYTE                *key,           // IN: key buffer. The size of this buffer in
503                                        //      bytes is (keySizeInBits + 7) / 8
504    BYTE                *iv,            // IN/OUT: IV for decryption.
505    UINT32               dInSize,       // IN: data size (is required to be a multiple
506                                        //      of 16 bytes)
507    BYTE                *dIn            // IN: data buffer
508    )
509{
510    SM4_KEY         Sm4Key;
511    BYTE           *pIv;
512    INT32           dSize;              // Need a signed version
513    int             i;
514    pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
515    if(dInSize == 0)
516        return CRYPT_SUCCESS;
517    pAssert(dInSize <= INT32_MAX);
518    dSize = (INT32)dInSize;
519    // For CBC, the data size must be an even multiple of the
520    // cipher block size
521    if((dSize % 16) != 0)
522        return CRYPT_PARAMETER;
523    // Create SM4 encrypt key schedule
524    if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
525        FAIL(FATAL_ERROR_INTERNAL);
526    // XOR the data block into the IV, encrypt the IV into the IV
527    // and then copy the IV to the output
528    for(; dSize > 0; dSize -= 16)
529    {
530        pIv = iv;
531        for(i = 16; i > 0; i--)
532            *pIv++ ^= *dIn++;
533        SM4_encrypt(iv, iv, &Sm4Key);
534        pIv = iv;
535        for(i = 16; i > 0; i--)
536            *dOut++ = *pIv++;
537    }
538    return CRYPT_SUCCESS;
539}
540//
541//
542//       _cpri__SM4DecryptCBC()
543//
544//      This function performs SM4 decryption in CBC chain mode. The input dIn buffer is decrypted into dOut.
545//      The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to
546//      be a multiple of the block size.
547//
548//      Return Value                     Meaning
549//
550//      CRYPT_SUCCESS                    if success
551//      CRYPT_PARAMETER                  dInSize is not a multiple of the block size
552//
553LIB_EXPORT CRYPT_RESULT
554_cpri__SM4DecryptCBC(
555    BYTE                *dOut,          // OUT: the decrypted data
556    UINT32               keySizeInBits, // IN: key size in bit
557    BYTE                *key,           // IN: key buffer. The size of this buffer in
558                                        //     bytes is (keySizeInBits + 7) / 8
559    BYTE                *iv,            // IN/OUT: IV for decryption. The size of this
560                                        //     buffer is 16 byte
561    UINT32               dInSize,       // IN: data size
562    BYTE                *dIn            // IN: data buffer
563    )
564{
565    SM4_KEY         Sm4Key;
566    BYTE           *pIv;
567    int             i;
568    BYTE            tmp[16];
569    BYTE           *pT = NULL;
570    INT32           dSize;
571    pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
572    if(dInSize == 0)
573        return CRYPT_SUCCESS;
574    pAssert(dInSize <= INT32_MAX);
575    dSize = (INT32)dInSize;
576    // For CBC, the data size must be an even multiple of the
577    // cipher block size
578    if((dSize % 16) != 0)
579        return CRYPT_PARAMETER;
580    // Create SM4 key schedule
581    if (SM4_set_decrypt_key(key, keySizeInBits, &Sm4Key) != 0)
582        FAIL(FATAL_ERROR_INTERNAL);
583    // Copy the input data to a temp buffer, decrypt the buffer into the output;
584    // XOR in the IV, and copy the temp buffer to the IV and repeat.
585    for(; dSize > 0; dSize -= 16)
586    {
587        pT = tmp;
588        for(i = 16; i> 0; i--)
589            *pT++ = *dIn++;
590        SM4_decrypt(tmp, dOut, &Sm4Key);
591        pIv = iv;
592        pT = tmp;
593        for(i = 16; i> 0; i--)
594        {
595            *dOut++ ^= *pIv;
596//
597              *pIv++ = *pT++;
598        }
599   }
600   return CRYPT_SUCCESS;
601}
602//
603//
604//       _cpri__SM4EncryptCFB()
605//
606//      This function performs SM4 encryption in CFB chain mode. The dOut buffer receives the values
607//      encrypted dIn. The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will
608//      be modified to contain the last encrypted block.
609//
610//      Return Value                      Meaning
611//
612//      CRYPT_SUCCESS                     no non-fatal errors
613//
614LIB_EXPORT CRYPT_RESULT
615_cpri__SM4EncryptCFB(
616   BYTE                *dOut,          // OUT: the encrypted
617   UINT32               keySizeInBits, // IN: key size in bit
618   BYTE                *key,           // IN: key buffer. The size of this buffer in
619                                       //     bytes is (keySizeInBits + 7) / 8
620   BYTE                *iv,            // IN/OUT: IV for decryption.
621   UINT32               dInSize,       // IN: data size
622   BYTE                *dIn            // IN: data buffer
623   )
624{
625   BYTE           *pIv;
626   SM4_KEY         Sm4Key;
627   INT32           dSize;               // Need a signed version of dInSize
628   int             i;
629   pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
630   if(dInSize == 0)
631       return CRYPT_SUCCESS;
632   pAssert(dInSize <= INT32_MAX);
633   dSize = (INT32)dInSize;
634   // Create SM4 encryption key schedule
635   if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
636       FAIL(FATAL_ERROR_INTERNAL);
637   // Encrypt the IV into the IV, XOR in the data, and copy to output
638   for(; dSize > 0; dSize -= 16)
639   {
640       // Encrypt the current value of the IV
641       SM4_encrypt(iv, iv, &Sm4Key);
642       pIv = iv;
643       for(i = (int)(dSize < 16) ? dSize : 16; i > 0; i--)
644           // XOR the data into the IV to create the cipher text
645           // and put into the output
646           *dOut++ = *pIv++ ^= *dIn++;
647   }
648   return CRYPT_SUCCESS;
649}
650//
651//
652//       _cpri__SM4DecryptCFB()
653//
654//      This function performs SM4 decrypt in CFB chain mode. The dOut buffer receives the values decrypted
655//      from dIn.
656//
657//      The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will be modified to
658//      contain the last decoded block, padded with zeros
659//
660//      Return Value                    Meaning
661//
662//      CRYPT_SUCCESS                   no non-fatal errors
663//
664LIB_EXPORT CRYPT_RESULT
665_cpri__SM4DecryptCFB(
666   BYTE                *dOut,          // OUT: the decrypted data
667   UINT32               keySizeInBits, // IN: key size in bit
668   BYTE                *key,           // IN: key buffer. The size of this buffer in
669                                       //     bytes is (keySizeInBits + 7) / 8
670   BYTE                *iv,            // IN/OUT: IV for decryption.
671   UINT32               dInSize,       // IN: data size
672   BYTE                *dIn            // IN: data buffer
673   )
674{
675   BYTE           *pIv;
676   BYTE            tmp[16];
677   int             i;
678   BYTE           *pT;
679   SM4_KEY         Sm4Key;
680   INT32           dSize;
681   pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
682   if(dInSize == 0)
683       return CRYPT_SUCCESS;
684   pAssert(dInSize <= INT32_MAX);
685   dSize = (INT32)dInSize;
686   // Create SM4 encryption key schedule
687   if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
688       FAIL(FATAL_ERROR_INTERNAL);
689   for(; dSize > 0; dSize -= 16)
690   {
691       // Encrypt the IV into the temp buffer
692       SM4_encrypt(iv, tmp, &Sm4Key);
693       pT = tmp;
694       pIv = iv;
695       for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
696           // Copy the current cipher text to IV, XOR
697           // with the temp buffer and put into the output
698           *dOut++ = *pT++ ^ (*pIv++ = *dIn++);
699   }
700   // If the inner loop (i loop) was smaller than 16, then dSize
701   // would have been smaller than 16 and it is now negative
702   // If it is negative, then it indicates how may fill bytes
703   // are needed to pad out the IV for the next round.
704   for(; dSize < 0; dSize++)
705       *iv++ = 0;
706   return CRYPT_SUCCESS;
707}
708//
709//
710//       _cpri__SM4EncryptCTR()
711//
712//      This function performs SM4 encryption/decryption in CTR chain mode. The dIn buffer is encrypted into
713//      dOut. The input iv buffer is assumed to have a size equal to the SM4 block size (16 bytes). The iv will be
714//      incremented by the number of blocks (full and partial) that were encrypted.
715//
716//      Return Value                      Meaning
717//
718//      CRYPT_SUCCESS                     no non-fatal errors
719//
720LIB_EXPORT CRYPT_RESULT
721_cpri__SM4EncryptCTR(
722   BYTE               *dOut,          // OUT: the encrypted data
723   UINT32              keySizeInBits, // IN: key size in bit
724   BYTE               *key,           // IN: key buffer. The size of this buffer in
725                                      //     bytes is (keySizeInBits + 7) / 8
726   BYTE               *iv,            // IN/OUT: IV for decryption.
727   UINT32              dInSize,       // IN: data size
728   BYTE               *dIn            // IN: data buffer
729   )
730{
731   BYTE            tmp[16];
732   BYTE           *pT;
733   SM4_KEY         Sm4Key;
734   int             i;
735   INT32           dSize;
736   pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
737   if(dInSize == 0)
738       return CRYPT_SUCCESS;
739   pAssert(dInSize <= INT32_MAX);
740   dSize = (INT32)dInSize;
741   // Create SM4 encryption schedule
742   if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
743       FAIL(FATAL_ERROR_INTERNAL);
744   for(; dSize > 0; dSize--)
745   {
746       // Encrypt the current value of the IV(counter)
747       SM4_encrypt(iv, (BYTE *)tmp, &Sm4Key);
748        //increment the counter
749        for(i = 0; i < 16; i++)
750            if((iv[i] += 1) != 0)
751                break;
752        // XOR the encrypted counter value with input and put into output
753        pT = tmp;
754        for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
755            *dOut++ = *dIn++ ^ *pT++;
756   }
757   return CRYPT_SUCCESS;
758}
759//
760//       _cpri__SM4EncryptECB()
761//
762//      SM4 encryption in ECB mode. The data buffer is modified to contain the cipher text.
763//
764//      Return Value                      Meaning
765//
766//      CRYPT_SUCCESS                     no non-fatal errors
767//
768LIB_EXPORT CRYPT_RESULT
769_cpri__SM4EncryptECB(
770    BYTE                *dOut,          // OUT: encrypted data
771    UINT32               keySizeInBits, // IN: key size in bit
772    BYTE                *key,           // IN: key buffer. The size of this buffer in
773                                        //     bytes is (keySizeInBits + 7) / 8
774    UINT32               dInSize,       // IN: data size
775    BYTE                *dIn            // IN: clear text buffer
776    )
777{
778    SM4_KEY          Sm4Key;
779    INT32            dSize;
780    pAssert(dOut != NULL && key != NULL && dIn != NULL);
781    if(dInSize == 0)
782        return CRYPT_SUCCESS;
783    pAssert(dInSize <= INT32_MAX);
784    dSize = (INT32)dInSize;
785    // For ECB, the data size must be an even multiple of the
786    // cipher block size
787    if((dSize % 16) != 0)
788        return CRYPT_PARAMETER;
789    // Create SM4 encrypting key schedule
790    if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
791        FAIL(FATAL_ERROR_INTERNAL);
792    for(; dSize > 0; dSize -= 16)
793    {
794        SM4_encrypt(dIn, dOut, &Sm4Key);
795        dIn = &dIn[16];
796        dOut = &dOut[16];
797    }
798    return CRYPT_SUCCESS;
799}
800//
801//
802//       _cpri__SM4DecryptECB()
803//
804//      This function performs SM4 decryption using ECB (not recommended). The cipher text dIn is decrypted
805//      into dOut.
806//
807//
808//
809//
810//      Return Value                      Meaning
811//
812//      CRYPT_SUCCESS                     no non-fatal errors
813//
814LIB_EXPORT CRYPT_RESULT
815_cpri__SM4DecryptECB(
816   BYTE                *dOut,          // OUT: the clear text data
817   UINT32               keySizeInBits, // IN: key size in bit
818   BYTE                *key,           // IN: key buffer. The size of this buffer in
819                                       //     bytes is (keySizeInBits + 7) / 8
820   UINT32               dInSize,       // IN: data size
821   BYTE                *dIn            // IN: cipher text buffer
822   )
823{
824   SM4_KEY         Sm4Key;
825   INT32           dSize;
826   pAssert(dOut != NULL && key != NULL && dIn != NULL);
827   if(dInSize == 0)
828       return CRYPT_SUCCESS;
829   pAssert(dInSize <= INT32_MAX);
830   dSize = (INT32)dInSize;
831   // For ECB, the data size must be an even multiple of the
832   // cipher block size
833   if((dSize % 16) != 0)
834       return CRYPT_PARAMETER;
835   // Create SM4 decryption key schedule
836   if (SM4_set_decrypt_key(key, keySizeInBits, &Sm4Key) != 0)
837       FAIL(FATAL_ERROR_INTERNAL);
838   for(; dSize > 0; dSize -= 16)
839   {
840       SM4_decrypt(dIn, dOut, &Sm4Key);
841       dIn = &dIn[16];
842       dOut = &dOut[16];
843   }
844   return CRYPT_SUCCESS;
845}
846//
847//
848//       _cpri__SM4EncryptOFB()
849//
850//      This function performs SM4 encryption/decryption in OFB chain mode. The dIn buffer is modified to
851//      contain the encrypted/decrypted text.
852//      The input iv buffer is assumed to have a size equal to the block size (16 bytes). The returned value of iv
853//      will be the nth encryption of the IV, where n is the number of blocks (full or partial) in the data stream.
854//
855//      Return Value                      Meaning
856//
857//      CRYPT_SUCCESS                     no non-fatal errors
858//
859LIB_EXPORT CRYPT_RESULT
860_cpri__SM4EncryptOFB(
861   BYTE                *dOut,          // OUT: the encrypted/decrypted data
862   UINT32               keySizeInBits, // IN: key size in bit
863   BYTE                *key,           // IN: key buffer. The size of this buffer in
864                                       //     bytes is (keySizeInBits + 7) / 8
865   BYTE                *iv,            // IN/OUT: IV for decryption. The size of this
866                                       //     buffer is 16 byte
867   UINT32              dInSize,         // IN: data size
868   BYTE               *dIn              // IN: data buffer
869   )
870{
871   BYTE           *pIv;
872   SM4_KEY         Sm4Key;
873   INT32           dSize;
874   int             i;
875   pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL);
876   if(dInSize == 0)
877       return CRYPT_SUCCESS;
878   pAssert(dInSize <= INT32_MAX);
879   dSize = (INT32)dInSize;
880   // Create SM4 key schedule
881   if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
882       FAIL(FATAL_ERROR_INTERNAL);
883   // This is written so that dIn and dOut may be the same
884   for(; dSize > 0; dSize -= 16)
885   {
886       // Encrypt the current value of the "IV"
887       SM4_encrypt(iv, iv, &Sm4Key);
888        // XOR the encrypted IV into dIn to create the cipher text (dOut)
889        pIv = iv;
890        for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
891            *dOut++ = (*pIv++ ^ *dIn++);
892   }
893   return CRYPT_SUCCESS;
894}
895#endif      //% TPM_ALG_SM4
896