components/krb5/Solaris/ucrypto/enc_provider/rc4.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/openssl/enc_provider/des.c */
       
     3 /*
       
     4  * Copyright (C) 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 /*
       
    28  * Copyright (C) 1998 by the FundsXpress, INC.
       
    29  *
       
    30  * All rights reserved.
       
    31  *
       
    32  * Export of this software from the United States of America may require
       
    33  * a specific license from the United States Government.  It is the
       
    34  * responsibility of any person or organization contemplating export to
       
    35  * obtain such a license before exporting.
       
    36  *
       
    37  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
       
    38  * distribute this software and its documentation for any purpose and
       
    39  * without fee is hereby granted, provided that the above copyright
       
    40  * notice appear in all copies and that both that copyright notice and
       
    41  * this permission notice appear in supporting documentation, and that
       
    42  * the name of FundsXpress. not be used in advertising or publicity pertaining
       
    43  * to distribution of the software without specific, written prior
       
    44  * permission.  FundsXpress makes no representations about the suitability of
       
    45  * this software for any purpose.  It is provided "as is" without express
       
    46  * or implied warranty.
       
    47  *
       
    48  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
       
    49  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
       
    50  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
       
    51  */
       
    52 /*
       
    53  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
       
    54  */
       
    55 
       
    56 #include "crypto_int.h"
       
    57 #include <libucrypto.h>
       
    58 
       
    59 /*
       
    60  * The loopback field is NULL if uctx is uninitialized (no encrypt or decrypt
       
    61  * operation has taken place), or is a pointer to the structure address if uctx
       
    62  * is initialized.  If an application copies the state (not a valid operation,
       
    63  * but one which happens to works with some other enc providers), we can detect
       
    64  * it via the loopback field and return a sane error code.
       
    65  */
       
    66 struct arcfour_state {
       
    67     struct arcfour_state *loopback;
       
    68     int op_type; /* encrypt, decrypt */
       
    69     crypto_ctx_t uctx; /* ucrypto context */
       
    70 };
       
    71 #define ENCRYPT_OP 1
       
    72 #define DECRYPT_OP 2
       
    73 
       
    74 #define RC4_KEY_SIZE 16
       
    75 #define RC4_BLOCK_SIZE 1
       
    76 
       
    77 static krb5_error_code
       
    78 k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
       
    79                    size_t num_data, int op_type)
       
    80 {
       
    81     int ret = 0;
       
    82     crypto_ctx_t local_uctx, *uctx; /* ucrypto context */
       
    83     size_t len, i;
       
    84     struct arcfour_state *arcstate;
       
    85     krb5_boolean do_init = TRUE;
       
    86 
       
    87     arcstate = (state != NULL) ? (struct arcfour_state *)state->data : NULL;
       
    88     if (arcstate != NULL) {
       
    89         /*
       
    90          * If loopback points to arcstate we know that uctx has been init'ed
       
    91          * but if it doesn't and it isn't NULL then arcstate has been corrupted
       
    92          * which means we can't trust that uctx is valid.
       
    93          */
       
    94         if (arcstate->loopback == arcstate)
       
    95             do_init = FALSE;
       
    96         else if (arcstate->loopback != NULL)
       
    97             return KRB5_CRYPTO_INTERNAL;
       
    98 
       
    99         uctx = &arcstate->uctx;
       
   100     } else {
       
   101         /* Use the local ucrypto context, will need to be cleaned up in this
       
   102          * function. */
       
   103         uctx = &local_uctx;
       
   104     }
       
   105 
       
   106     if (do_init) {
       
   107         if (op_type == ENCRYPT_OP) {
       
   108             if (ucrypto_encrypt_init(uctx, CRYPTO_RC4,
       
   109                                      key->keyblock.contents,
       
   110                                      key->keyblock.length,
       
   111                                      NULL, 0) != CRYPTO_SUCCESS) {
       
   112                 return KRB5_CRYPTO_INTERNAL;
       
   113             }
       
   114         } else {
       
   115             if (ucrypto_decrypt_init(uctx, CRYPTO_RC4,
       
   116                                      key->keyblock.contents,
       
   117                                      key->keyblock.length,
       
   118                                      NULL, 0) != CRYPTO_SUCCESS) {
       
   119                 return KRB5_CRYPTO_INTERNAL;
       
   120             }
       
   121         }
       
   122 
       
   123         /* Saved ucrypto context is init'ed, mark as initialized. */
       
   124         if (arcstate) {
       
   125             arcstate->loopback = arcstate;
       
   126             arcstate->op_type = op_type;
       
   127         }
       
   128     }
       
   129 
       
   130     for (i = 0; i < num_data; i++) {
       
   131         krb5_crypto_iov *iov = &data[i];
       
   132 
       
   133         if (ENCRYPT_IOV(iov)) {
       
   134             len = (size_t)iov->data.length;
       
   135 
       
   136             if (op_type == ENCRYPT_OP) {
       
   137                 if (ucrypto_encrypt_update(uctx,
       
   138                                            (const uchar_t *)iov->data.data,
       
   139                                            len,
       
   140                                            (uchar_t *)iov->data.data,
       
   141                                            &len) != CRYPTO_SUCCESS) {
       
   142                     ret = KRB5_CRYPTO_INTERNAL;
       
   143                     break;
       
   144                 }
       
   145             } else {
       
   146                 if (ucrypto_decrypt_update(uctx,
       
   147                                            (const uchar_t *)iov->data.data,
       
   148                                            len,
       
   149                                            (uchar_t *)iov->data.data,
       
   150                                            &len) != CRYPTO_SUCCESS) {
       
   151                     ret = KRB5_CRYPTO_INTERNAL;
       
   152                     break;
       
   153                 }
       
   154             }
       
   155         }
       
   156     }
       
   157 
       
   158     if (!arcstate) {
       
   159         /* Local ucrypto context is not saved, clean it up now. */
       
   160         len = 0;
       
   161         if (op_type == ENCRYPT_OP)
       
   162             (void)ucrypto_encrypt_final(uctx, NULL, &len);
       
   163         else
       
   164             (void)ucrypto_decrypt_final(uctx, NULL, &len);
       
   165     }
       
   166 
       
   167     return ret;
       
   168 }
       
   169 
       
   170 static krb5_error_code
       
   171 k5_arcfour_encrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
       
   172                    size_t num_data)
       
   173 {
       
   174     return k5_arcfour_docrypt(key, state, data, num_data, ENCRYPT_OP);
       
   175 }
       
   176 
       
   177 static krb5_error_code
       
   178 k5_arcfour_decrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
       
   179                    size_t num_data)
       
   180 {
       
   181     return k5_arcfour_docrypt(key, state, data, num_data, DECRYPT_OP);
       
   182 }
       
   183 
       
   184 static krb5_error_code
       
   185 krb5int_arcfour_init_state(const krb5_keyblock *key, krb5_keyusage usage,
       
   186                            krb5_data *state)
       
   187 {
       
   188     struct arcfour_state *arcstate;
       
   189 
       
   190     arcstate = calloc(1, sizeof (*arcstate));
       
   191     if (arcstate == NULL)
       
   192         return ENOMEM;
       
   193 
       
   194     state->data = (char *)arcstate;
       
   195     state->length = sizeof (*arcstate);
       
   196 
       
   197     return 0;
       
   198 }
       
   199 
       
   200 static void
       
   201 krb5int_arcfour_free_state(krb5_data *state)
       
   202 {
       
   203     struct arcfour_state *arcstate = (struct arcfour_state *)state->data;
       
   204 
       
   205     /* If arcstate->loopback == arcstate then the ucrypto context was init'ed
       
   206      * and uctx clean up is required. */
       
   207     if (arcstate && arcstate->loopback == arcstate) {
       
   208         size_t len = 0;
       
   209 
       
   210         if (arcstate->op_type == ENCRYPT_OP)
       
   211             (void) ucrypto_encrypt_final(&arcstate->uctx, NULL, &len);
       
   212         else
       
   213             (void) ucrypto_decrypt_final(&arcstate->uctx, NULL, &len);
       
   214     }
       
   215 
       
   216     free(arcstate);
       
   217     state->data = NULL;
       
   218     state->length = 0;
       
   219 
       
   220     return;
       
   221 }
       
   222 
       
   223 const struct krb5_enc_provider krb5int_enc_arcfour = {
       
   224     /* This seems to work... although I am not sure what the
       
   225        implications are in other places in the kerberos library */
       
   226     RC4_BLOCK_SIZE,
       
   227     /* Keysize is arbitrary in arcfour, but the constraints of the
       
   228        system, and to attempt to work with the MSFT system forces us
       
   229        to 16byte/128bit.  Since there is no parity in the key, the
       
   230        byte and length are the same.  */
       
   231     RC4_KEY_SIZE, RC4_KEY_SIZE,
       
   232     k5_arcfour_encrypt,
       
   233     k5_arcfour_decrypt,
       
   234     NULL,
       
   235     krb5int_arcfour_init_state,
       
   236     krb5int_arcfour_free_state
       
   237 };