components/krb5/Solaris/ucrypto/enc_provider/camellia.c
changeset 7950 50d75ee82dad
equal deleted inserted replaced
7949:e94c44902e51 7950:50d75ee82dad
       
     1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
       
     2 /* lib/crypto/ucrypto/enc_provider/aes.c */
       
     3 /*
       
     4  * Copyright (C) 2003, 2007, 2008, 2009 by the Massachusetts Institute of Technology.
       
     5  * All rights reserved.
       
     6  *
       
     7  * Export of this software from the United States of America may
       
     8  *   require a specific license from the United States Government.
       
     9  *   It is the responsibility of any person or organization contemplating
       
    10  *   export to obtain such a license before exporting.
       
    11  *
       
    12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
       
    13  * distribute this software and its documentation for any purpose and
       
    14  * without fee is hereby granted, provided that the above copyright
       
    15  * notice appear in all copies and that both that copyright notice and
       
    16  * this permission notice appear in supporting documentation, and that
       
    17  * the name of M.I.T. not be used in advertising or publicity pertaining
       
    18  * to distribution of the software without specific, written prior
       
    19  * permission.  Furthermore if you modify this software you must label
       
    20  * your software as modified software and not distribute it in such a
       
    21  * fashion that it might be confused with the original M.I.T. software.
       
    22  * M.I.T. makes no representations about the suitability of
       
    23  * this software for any purpose.  It is provided "as is" without express
       
    24  * or implied warranty.
       
    25  */
       
    26 /*
       
    27  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
       
    28  */
       
    29 
       
    30 #include "crypto_int.h"
       
    31 #include <libucrypto.h>
       
    32 
       
    33 #define BLOCK_SIZE 16
       
    34 
       
    35 #define ENCRYPT_OP 1
       
    36 #define DECRYPT_OP 2
       
    37 
       
    38 /*
       
    39  * xorblock is used in the camellia cbc mac fuction, copied from the openssl
       
    40  * camellia.c.
       
    41  */
       
    42 static void
       
    43 xorblock(unsigned char *out, const unsigned char *in)
       
    44 {
       
    45     int z;
       
    46     for (z = 0; z < BLOCK_SIZE / 4; z++) {
       
    47         unsigned char *outptr = &out[z * 4];
       
    48         unsigned char *inptr = (unsigned char *)&in[z * 4];
       
    49         /*
       
    50          * Use unaligned accesses.  On x86, this will probably still be faster
       
    51          * than multiple byte accesses for unaligned data, and for aligned data
       
    52          * should be far better.  (One test indicated about 2.4% faster
       
    53          * encryption for 1024-byte messages.)
       
    54          *
       
    55          * If some other CPU has really slow unaligned-word or byte accesses,
       
    56          * perhaps this function (or the load/store helpers?) should test for
       
    57          * alignment first.
       
    58          *
       
    59          * If byte accesses are faster than unaligned words, we may need to
       
    60          * conditionalize on CPU type, as that may be hard to determine
       
    61          * automatically.
       
    62          */
       
    63         store_32_n(load_32_n(outptr) ^ load_32_n(inptr), outptr);
       
    64     }
       
    65 }
       
    66 
       
    67 /*
       
    68  * The cbc_docrypt function is here to handle the case where there is only 1
       
    69  * block of plain/cipher text to process.
       
    70  */
       
    71 static krb5_error_code
       
    72 cbc_docrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
       
    73             size_t num_data, int op_type)
       
    74 {
       
    75     int                    ret = 0;
       
    76     unsigned char          iblock[BLOCK_SIZE], oblock[BLOCK_SIZE];
       
    77     size_t                 olen = sizeof (oblock);
       
    78     unsigned char          tmp_iv[BLOCK_SIZE];
       
    79     struct iov_cursor      cursor;
       
    80 
       
    81     if (ivec && ivec->data){
       
    82         if (ivec->length != sizeof (tmp_iv))
       
    83             return KRB5_CRYPTO_INTERNAL;
       
    84         memcpy(tmp_iv, ivec->data, ivec->length);
       
    85     } else {
       
    86         memset(tmp_iv, 0, sizeof (tmp_iv));
       
    87     }
       
    88 
       
    89     /* Init iovec cursor to gather data for encypting (FALSE) */
       
    90     k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
       
    91     k5_iov_cursor_get(&cursor, iblock);
       
    92 
       
    93     if (op_type == ENCRYPT_OP) {
       
    94         if (ucrypto_encrypt(CRYPTO_CAMELLIA_CBC,
       
    95                             key->keyblock.contents,
       
    96                             key->keyblock.length,
       
    97                             tmp_iv, sizeof (tmp_iv),
       
    98                             iblock, sizeof (iblock),
       
    99                             oblock, &olen) != CRYPTO_SUCCESS) {
       
   100             ret = KRB5_CRYPTO_INTERNAL;
       
   101         }
       
   102     } else {
       
   103         if (ucrypto_decrypt(CRYPTO_CAMELLIA_CBC,
       
   104                             key->keyblock.contents,
       
   105                             key->keyblock.length,
       
   106                             tmp_iv, sizeof (tmp_iv),
       
   107                             iblock, sizeof (iblock),
       
   108                             oblock, &olen) != CRYPTO_SUCCESS) {
       
   109             ret = KRB5_CRYPTO_INTERNAL;
       
   110         }
       
   111     }
       
   112 
       
   113     if (!ret) {
       
   114         assert(olen == BLOCK_SIZE);
       
   115         k5_iov_cursor_put(&cursor, oblock);
       
   116 
       
   117         if (ivec && ivec->data) {
       
   118             if (op_type == ENCRYPT_OP)
       
   119                 memcpy(ivec->data, oblock, BLOCK_SIZE);
       
   120             else
       
   121                 memcpy(ivec->data, iblock, BLOCK_SIZE);
       
   122         }
       
   123     }
       
   124 
       
   125     zap(iblock, sizeof (iblock));
       
   126     zap(oblock, sizeof (oblock));
       
   127 
       
   128     return ret;
       
   129 }
       
   130 
       
   131 static krb5_error_code
       
   132 cts_docrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
       
   133             size_t num_data, size_t dlen, size_t dblks, int op_type)
       
   134 {
       
   135     int                    ret = 0;
       
   136     size_t                 olen = dlen;
       
   137     unsigned char         *obuf, *dbuf;
       
   138     unsigned char          iv_cts[BLOCK_SIZE];
       
   139     struct iov_cursor      cursor;
       
   140 
       
   141     if (ivec && ivec->data){
       
   142         if (ivec->length != sizeof (iv_cts))
       
   143             return KRB5_CRYPTO_INTERNAL;
       
   144         memcpy(iv_cts, ivec->data, ivec->length);
       
   145     } else {
       
   146         memset(iv_cts, 0, sizeof (iv_cts));
       
   147     }
       
   148 
       
   149     obuf = malloc(olen);
       
   150     if (!obuf)
       
   151         return ENOMEM;
       
   152 
       
   153     dbuf = malloc(dlen);
       
   154     if (!dbuf){
       
   155         free(obuf);
       
   156         return ENOMEM;
       
   157     }
       
   158 
       
   159     /* Init iov cursor to gather data for encypting/decrypting (FALSE) */
       
   160     k5_iov_cursor_init(&cursor, data, num_data, dlen, FALSE);
       
   161     /* Get all the data to be encrypted/decrypted into dbuf */
       
   162     k5_iov_cursor_get(&cursor, dbuf);
       
   163 
       
   164     if (op_type == ENCRYPT_OP) {
       
   165         if (ucrypto_encrypt(CRYPTO_CAMELLIA_CTS,
       
   166                             key->keyblock.contents,
       
   167                             key->keyblock.length,
       
   168                             iv_cts, sizeof (iv_cts),
       
   169                             dbuf, dlen, obuf, &olen) != CRYPTO_SUCCESS) {
       
   170             ret = KRB5_CRYPTO_INTERNAL;
       
   171         }
       
   172     } else {
       
   173         if (ucrypto_decrypt(CRYPTO_CAMELLIA_CTS,
       
   174                             key->keyblock.contents,
       
   175                             key->keyblock.length,
       
   176                             iv_cts, sizeof (iv_cts),
       
   177                             dbuf, dlen, obuf, &olen) != CRYPTO_SUCCESS) {
       
   178             ret = KRB5_CRYPTO_INTERNAL;
       
   179         }
       
   180     }
       
   181 
       
   182     if (!ret) {
       
   183         assert(olen == dlen);
       
   184         k5_iov_cursor_put(&cursor, obuf);
       
   185         /*
       
   186          * Updating the ivec arg, if present because of an old/obscure concept
       
   187          * of cipher state that is being used by only BSD rlogin.  See RFCs
       
   188          * 1391 and 1392 in regards to the vague description of cipher state.
       
   189          * For encrypt/decrypt use the second to the last block of ciphertext
       
   190          * if > 1 block.
       
   191          */
       
   192         if (ivec && ivec->data) {
       
   193             unsigned char *bufptr = (op_type == ENCRYPT_OP) ? obuf : dbuf;
       
   194             /*
       
   195              * For encrypt obuf is ciphertext, for decrypt its dbuf which was
       
   196              * input.
       
   197              */
       
   198             memcpy(ivec->data, bufptr + ((dblks - 2) * BLOCK_SIZE),
       
   199                    BLOCK_SIZE);
       
   200         }
       
   201     }
       
   202 
       
   203     zapfree(obuf, olen);
       
   204     zapfree(dbuf, dlen);
       
   205 
       
   206     return ret;
       
   207 }
       
   208 
       
   209 krb5_error_code
       
   210 krb5int_camellia_encrypt(krb5_key key, const krb5_data *ivec,
       
   211                     krb5_crypto_iov *data, size_t num_data)
       
   212 {
       
   213     size_t input_length, nblocks;
       
   214 
       
   215     input_length = iov_total_length(data, num_data, FALSE);
       
   216     nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
       
   217     if (nblocks == 1) {
       
   218         if (input_length != BLOCK_SIZE)
       
   219             return KRB5_BAD_MSIZE;
       
   220         /*
       
   221 	 * Note, there is bug here (see MIT bug ticket 8551 Crypto providers not
       
   222 	 * updating cipher state when 1 block plaintext is encrypted) hence the
       
   223 	 * NULL ivec arg.  For now we leave the bug in since it has existed in
       
   224 	 * MIT code a long time and the tests need the buggy behavior to pass at
       
   225 	 * this point.
       
   226          */
       
   227         return cbc_docrypt(key, NULL, data, num_data, ENCRYPT_OP);
       
   228     } else {  /* nblocks > 1 */
       
   229         return cts_docrypt(key, ivec, data, num_data, input_length, nblocks,
       
   230                            ENCRYPT_OP);
       
   231     }
       
   232 }
       
   233 
       
   234 krb5_error_code
       
   235 krb5int_camellia_decrypt(krb5_key key, const krb5_data *ivec,
       
   236                     krb5_crypto_iov *data, size_t num_data)
       
   237 {
       
   238     size_t input_length, nblocks;
       
   239 
       
   240     input_length = iov_total_length(data, num_data, FALSE);
       
   241     nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
       
   242     if (nblocks == 1) {
       
   243         if (input_length != BLOCK_SIZE)
       
   244             return KRB5_BAD_MSIZE;
       
   245         return cbc_docrypt(key, NULL, data, num_data, DECRYPT_OP);
       
   246     } else {  /* nblocks > 1 */
       
   247         return cts_docrypt(key, ivec, data, num_data, input_length, nblocks,
       
   248                            DECRYPT_OP);
       
   249     }
       
   250 }
       
   251 
       
   252 /*
       
   253  * This function is based on the openssl enc_provider/camellia.c version.
       
   254  */
       
   255 krb5_error_code
       
   256 krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
       
   257                          size_t num_data, const krb5_data *ivec,
       
   258                          krb5_data *output)
       
   259 {
       
   260     unsigned char blockY[BLOCK_SIZE], blockB[BLOCK_SIZE];
       
   261     size_t        olen = BLOCK_SIZE;
       
   262     struct iov_cursor cursor;
       
   263 
       
   264     if (output->length < BLOCK_SIZE)
       
   265         return KRB5_BAD_MSIZE;
       
   266 
       
   267     if (ivec != NULL && ivec->data != NULL)
       
   268         memcpy(blockY, ivec->data, BLOCK_SIZE);
       
   269     else
       
   270         memset(blockY, 0, BLOCK_SIZE);
       
   271 
       
   272     k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
       
   273     while (k5_iov_cursor_get(&cursor, blockB)) {
       
   274         xorblock(blockB, blockY);
       
   275         olen = sizeof(blockY);
       
   276         if (ucrypto_encrypt(CRYPTO_CAMELLIA_ECB,
       
   277                             key->keyblock.contents,
       
   278                             key->keyblock.length,
       
   279                             NULL, 0,
       
   280                             blockB, sizeof(blockB),
       
   281                             blockY, &olen) != CRYPTO_SUCCESS) {
       
   282             return KRB5_CRYPTO_INTERNAL;
       
   283         }
       
   284     }
       
   285 
       
   286     assert(olen == BLOCK_SIZE);
       
   287     output->length = BLOCK_SIZE;
       
   288     memcpy(output->data, blockY, BLOCK_SIZE);
       
   289 
       
   290     return 0;
       
   291 }
       
   292 
       
   293 static krb5_error_code
       
   294 krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
       
   295                         krb5_data *state)
       
   296 {
       
   297     state->data = calloc(1, BLOCK_SIZE);
       
   298     if (state->data == NULL)
       
   299         return ENOMEM;
       
   300     state->length = BLOCK_SIZE;
       
   301     return 0;
       
   302 }
       
   303 
       
   304 const struct krb5_enc_provider krb5int_enc_camellia128 = {
       
   305     BLOCK_SIZE,
       
   306     16, 16,
       
   307     krb5int_camellia_encrypt,
       
   308     krb5int_camellia_decrypt,
       
   309     krb5int_camellia_cbc_mac,
       
   310     krb5int_camellia_init_state,
       
   311     krb5int_default_free_state
       
   312 };
       
   313 
       
   314 const struct krb5_enc_provider krb5int_enc_camellia256 = {
       
   315     BLOCK_SIZE,
       
   316     32, 32,
       
   317     krb5int_camellia_encrypt,
       
   318     krb5int_camellia_decrypt,
       
   319     krb5int_camellia_cbc_mac,
       
   320     krb5int_camellia_init_state,
       
   321     krb5int_default_free_state
       
   322 };