"Fossies" - the Fresh Open Source Software Archive

Member "nss-3.37.3/nss/lib/freebl/aeskeywrap.c" (5 Jun 2018, 11427 Bytes) of package /linux/misc/nss-3.37.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "aeskeywrap.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    7 
    8 #ifdef FREEBL_NO_DEPEND
    9 #include "stubs.h"
   10 #endif
   11 
   12 #include "prcpucfg.h"
   13 #if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG)
   14 #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0
   15 #else
   16 #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1
   17 #endif
   18 #include "prtypes.h" /* for PRUintXX */
   19 #include "secport.h" /* for PORT_XXX */
   20 #include "secerr.h"
   21 #include "blapi.h" /* for AES_ functions */
   22 #include "rijndael.h"
   23 
   24 struct AESKeyWrapContextStr {
   25     AESContext aescx;
   26     unsigned char iv[AES_KEY_WRAP_IV_BYTES];
   27     void *mem; /* Pointer to beginning of allocated memory. */
   28 };
   29 
   30 /******************************************/
   31 /*
   32 ** AES key wrap algorithm, RFC 3394
   33 */
   34 
   35 AESKeyWrapContext *
   36 AESKeyWrap_AllocateContext(void)
   37 {
   38     /* aligned_alloc is C11 so we have to do it the old way. */
   39     AESKeyWrapContext *ctx = PORT_ZAlloc(sizeof(AESKeyWrapContext) + 15);
   40     if (ctx == NULL) {
   41         PORT_SetError(SEC_ERROR_NO_MEMORY);
   42         return NULL;
   43     }
   44     ctx->mem = ctx;
   45     return (AESKeyWrapContext *)(((uintptr_t)ctx + 15) & ~(uintptr_t)0x0F);
   46 }
   47 
   48 SECStatus
   49 AESKeyWrap_InitContext(AESKeyWrapContext *cx,
   50                        const unsigned char *key,
   51                        unsigned int keylen,
   52                        const unsigned char *iv,
   53                        int x1,
   54                        unsigned int encrypt,
   55                        unsigned int x2)
   56 {
   57     SECStatus rv = SECFailure;
   58     if (!cx) {
   59         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   60         return SECFailure;
   61     }
   62     if (iv) {
   63         memcpy(cx->iv, iv, sizeof cx->iv);
   64     } else {
   65         memset(cx->iv, 0xA6, sizeof cx->iv);
   66     }
   67     rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt,
   68                          AES_BLOCK_SIZE);
   69     return rv;
   70 }
   71 
   72 /*
   73 ** Create a new AES context suitable for AES encryption/decryption.
   74 **  "key" raw key data
   75 **  "keylen" the number of bytes of key data (16, 24, or 32)
   76 */
   77 extern AESKeyWrapContext *
   78 AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv,
   79                          int encrypt, unsigned int keylen)
   80 {
   81     SECStatus rv;
   82     AESKeyWrapContext *cx = AESKeyWrap_AllocateContext();
   83     if (!cx)
   84         return NULL; /* error is already set */
   85     rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0);
   86     if (rv != SECSuccess) {
   87         PORT_Free(cx->mem);
   88         cx = NULL; /* error should already be set */
   89     }
   90     return cx;
   91 }
   92 
   93 /*
   94 ** Destroy a AES KeyWrap context.
   95 **  "cx" the context
   96 **  "freeit" if PR_TRUE then free the object as well as its sub-objects
   97 */
   98 extern void
   99 AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
  100 {
  101     if (cx) {
  102         AES_DestroyContext(&cx->aescx, PR_FALSE);
  103         /*  memset(cx, 0, sizeof *cx); */
  104         if (freeit) {
  105             PORT_Free(cx->mem);
  106         }
  107     }
  108 }
  109 
  110 #if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
  111 
  112 /* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian
  113 ** (Most significant byte first) in memory.  The only ALU operations done
  114 ** on them are increment, decrement, and XOR.  So, on little-endian CPUs,
  115 ** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations
  116 ** are simulated in the following code.  This is thought to be faster and
  117 ** simpler than trying to convert the data to little-endian and back.
  118 */
  119 
  120 /* A and T point to two 64-bit values stored most signficant byte first
  121 ** (big endian).  This function increments the 64-bit value T, and then
  122 ** XORs it with A, changing A.
  123 */
  124 static void
  125 increment_and_xor(unsigned char *A, unsigned char *T)
  126 {
  127     if (!++T[7])
  128         if (!++T[6])
  129             if (!++T[5])
  130                 if (!++T[4])
  131                     if (!++T[3])
  132                         if (!++T[2])
  133                             if (!++T[1])
  134                                 ++T[0];
  135 
  136     A[0] ^= T[0];
  137     A[1] ^= T[1];
  138     A[2] ^= T[2];
  139     A[3] ^= T[3];
  140     A[4] ^= T[4];
  141     A[5] ^= T[5];
  142     A[6] ^= T[6];
  143     A[7] ^= T[7];
  144 }
  145 
  146 /* A and T point to two 64-bit values stored most signficant byte first
  147 ** (big endian).  This function XORs T with A, giving a new A, then
  148 ** decrements the 64-bit value T.
  149 */
  150 static void
  151 xor_and_decrement(PRUint64 *A, PRUint64 *T)
  152 {
  153     unsigned char *TP = (unsigned char *)T;
  154     const PRUint64 mask = 0xFF;
  155     *A = ((*A & mask << 56) ^ (*T & mask << 56)) |
  156          ((*A & mask << 48) ^ (*T & mask << 48)) |
  157          ((*A & mask << 40) ^ (*T & mask << 40)) |
  158          ((*A & mask << 32) ^ (*T & mask << 32)) |
  159          ((*A & mask << 24) ^ (*T & mask << 23)) |
  160          ((*A & mask << 16) ^ (*T & mask << 16)) |
  161          ((*A & mask << 8) ^ (*T & mask << 8)) |
  162          ((*A & mask) ^ (*T & mask));
  163 
  164     if (!TP[7]--)
  165         if (!TP[6]--)
  166             if (!TP[5]--)
  167                 if (!TP[4]--)
  168                     if (!TP[3]--)
  169                         if (!TP[2]--)
  170                             if (!TP[1]--)
  171                                 TP[0]--;
  172 }
  173 
  174 /* Given an unsigned long t (in host byte order), store this value as a
  175 ** 64-bit big-endian value (MSB first) in *pt.
  176 */
  177 static void
  178 set_t(unsigned char *pt, unsigned long t)
  179 {
  180     pt[7] = (unsigned char)t;
  181     t >>= 8;
  182     pt[6] = (unsigned char)t;
  183     t >>= 8;
  184     pt[5] = (unsigned char)t;
  185     t >>= 8;
  186     pt[4] = (unsigned char)t;
  187     t >>= 8;
  188     pt[3] = (unsigned char)t;
  189     t >>= 8;
  190     pt[2] = (unsigned char)t;
  191     t >>= 8;
  192     pt[1] = (unsigned char)t;
  193     t >>= 8;
  194     pt[0] = (unsigned char)t;
  195 }
  196 
  197 #endif
  198 
  199 /*
  200 ** Perform AES key wrap.
  201 **  "cx" the context
  202 **  "output" the output buffer to store the encrypted data.
  203 **  "outputLen" how much data is stored in "output". Set by the routine
  204 **     after some data is stored in output.
  205 **  "maxOutputLen" the maximum amount of data that can ever be
  206 **     stored in "output"
  207 **  "input" the input data
  208 **  "inputLen" the amount of input data
  209 */
  210 extern SECStatus
  211 AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
  212                    unsigned int *pOutputLen, unsigned int maxOutputLen,
  213                    const unsigned char *input, unsigned int inputLen)
  214 {
  215     PRUint64 *R = NULL;
  216     unsigned int nBlocks;
  217     unsigned int i, j;
  218     unsigned int aesLen = AES_BLOCK_SIZE;
  219     unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE;
  220     SECStatus s = SECFailure;
  221     /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
  222     PRUint64 t;
  223     PRUint64 B[2];
  224 
  225 #define A B[0]
  226 
  227     /* Check args */
  228     if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
  229         PORT_SetError(SEC_ERROR_INPUT_LEN);
  230         return s;
  231     }
  232 #ifdef maybe
  233     if (!output && pOutputLen) { /* caller is asking for output size */
  234         *pOutputLen = outLen;
  235         return SECSuccess;
  236     }
  237 #endif
  238     if (maxOutputLen < outLen) {
  239         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  240         return s;
  241     }
  242     if (cx == NULL || output == NULL || input == NULL) {
  243         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  244         return s;
  245     }
  246     nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
  247     R = PORT_NewArray(PRUint64, nBlocks + 1);
  248     if (!R)
  249         return s; /* error is already set. */
  250     /*
  251     ** 1) Initialize variables.
  252     */
  253     memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
  254     memcpy(&R[1], input, inputLen);
  255 #if BIG_ENDIAN_WITH_64_BIT_REGISTERS
  256     t = 0;
  257 #else
  258     memset(&t, 0, sizeof t);
  259 #endif
  260     /*
  261     ** 2) Calculate intermediate values.
  262     */
  263     for (j = 0; j < 6; ++j) {
  264         for (i = 1; i <= nBlocks; ++i) {
  265             B[1] = R[i];
  266             s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen,
  267                             sizeof B, (unsigned char *)B, sizeof B);
  268             if (s != SECSuccess)
  269                 break;
  270             R[i] = B[1];
  271 /* here, increment t and XOR A with t (in big endian order); */
  272 #if BIG_ENDIAN_WITH_64_BIT_REGISTERS
  273             A ^= ++t;
  274 #else
  275             increment_and_xor((unsigned char *)&A, (unsigned char *)&t);
  276 #endif
  277         }
  278     }
  279     /*
  280     ** 3) Output the results.
  281     */
  282     if (s == SECSuccess) {
  283         R[0] = A;
  284         memcpy(output, &R[0], outLen);
  285         if (pOutputLen)
  286             *pOutputLen = outLen;
  287     } else if (pOutputLen) {
  288         *pOutputLen = 0;
  289     }
  290     PORT_ZFree(R, outLen);
  291     return s;
  292 }
  293 #undef A
  294 
  295 /*
  296 ** Perform AES key unwrap.
  297 **  "cx" the context
  298 **  "output" the output buffer to store the decrypted data.
  299 **  "outputLen" how much data is stored in "output". Set by the routine
  300 **     after some data is stored in output.
  301 **  "maxOutputLen" the maximum amount of data that can ever be
  302 **     stored in "output"
  303 **  "input" the input data
  304 **  "inputLen" the amount of input data
  305 */
  306 extern SECStatus
  307 AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
  308                    unsigned int *pOutputLen, unsigned int maxOutputLen,
  309                    const unsigned char *input, unsigned int inputLen)
  310 {
  311     PRUint64 *R = NULL;
  312     unsigned int nBlocks;
  313     unsigned int i, j;
  314     unsigned int aesLen = AES_BLOCK_SIZE;
  315     unsigned int outLen;
  316     SECStatus s = SECFailure;
  317     /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
  318     PRUint64 t;
  319     PRUint64 B[2];
  320 
  321     /* Check args */
  322     if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE ||
  323         0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
  324         PORT_SetError(SEC_ERROR_INPUT_LEN);
  325         return s;
  326     }
  327     outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
  328 #ifdef maybe
  329     if (!output && pOutputLen) { /* caller is asking for output size */
  330         *pOutputLen = outLen;
  331         return SECSuccess;
  332     }
  333 #endif
  334     if (maxOutputLen < outLen) {
  335         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  336         return s;
  337     }
  338     if (cx == NULL || output == NULL || input == NULL) {
  339         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  340         return s;
  341     }
  342     nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
  343     R = PORT_NewArray(PRUint64, nBlocks);
  344     if (!R)
  345         return s; /* error is already set. */
  346     nBlocks--;
  347     /*
  348     ** 1) Initialize variables.
  349     */
  350     memcpy(&R[0], input, inputLen);
  351     B[0] = R[0];
  352 #if BIG_ENDIAN_WITH_64_BIT_REGISTERS
  353     t = 6UL * nBlocks;
  354 #else
  355     set_t((unsigned char *)&t, 6UL * nBlocks);
  356 #endif
  357     /*
  358     ** 2) Calculate intermediate values.
  359     */
  360     for (j = 0; j < 6; ++j) {
  361         for (i = nBlocks; i; --i) {
  362 /* here, XOR A with t (in big endian order) and decrement t; */
  363 #if BIG_ENDIAN_WITH_64_BIT_REGISTERS
  364             B[0] ^= t--;
  365 #else
  366             xor_and_decrement(&B[0], &t);
  367 #endif
  368             B[1] = R[i];
  369             s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen,
  370                             sizeof B, (unsigned char *)B, sizeof B);
  371             if (s != SECSuccess)
  372                 break;
  373             R[i] = B[1];
  374         }
  375     }
  376     /*
  377     ** 3) Output the results.
  378     */
  379     if (s == SECSuccess) {
  380         int bad = memcmp(&B[0], cx->iv, AES_KEY_WRAP_IV_BYTES);
  381         if (!bad) {
  382             memcpy(output, &R[1], outLen);
  383             if (pOutputLen)
  384                 *pOutputLen = outLen;
  385         } else {
  386             s = SECFailure;
  387             PORT_SetError(SEC_ERROR_BAD_DATA);
  388             if (pOutputLen)
  389                 *pOutputLen = 0;
  390         }
  391     } else if (pOutputLen) {
  392         *pOutputLen = 0;
  393     }
  394     PORT_ZFree(R, inputLen);
  395     return s;
  396 }
  397 #undef A