r23456: Update Samba4 to current lorikeet-heimdal.
[samba.git] / source4 / heimdal / lib / krb5 / crypto.c
index 6d4a81baa8c4332e56afdd6239d7dee6d8e4f2a7..93f3e44ba1c34050d57bc3141b5ac79986114cd3 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 #include "krb5_locl.h"
-RCSID("$Id: crypto.c,v 1.146 2006/11/17 21:58:47 lha Exp $");
+RCSID("$Id: crypto.c 20981 2007-06-07 20:05:50Z lha $");
 
 #undef CRYPTO_DEBUG
 #ifdef CRYPTO_DEBUG
@@ -57,8 +57,6 @@ struct krb5_crypto_data {
     struct key_usage *key_usage;
 };
 
-#define kcrypto_oid_enc(n) { sizeof(n)/sizeof(n[0]), n }
-
 #define CRYPTO_ETYPE(C) ((C)->et->type)
 
 /* bits for `flags' below */
@@ -82,7 +80,6 @@ struct key_type {
     const char *name;
     size_t bits;
     size_t size;
-    size_t minsize;
     size_t schedule_size;
 #if 0
     krb5_enctype best_etype;
@@ -128,6 +125,9 @@ struct encryption_type {
                               krb5_boolean encryptp,
                               int usage,
                               void *ivec);
+    size_t prf_length;
+    krb5_error_code (*prf)(krb5_context,
+                          krb5_crypto, const krb5_data *, krb5_data *);
 };
 
 #define ENCRYPTION_USAGE(U) (((U) << 8) | 0xAA)
@@ -724,7 +724,6 @@ static struct key_type keytype_null = {
     0,
     0,
     0,
-    0,
     NULL,
     NULL,
     NULL
@@ -735,7 +734,6 @@ static struct key_type keytype_des = {
     "des",
     56,
     sizeof(DES_cblock),
-    sizeof(DES_cblock),
     sizeof(DES_key_schedule),
     krb5_DES_random_key,
     krb5_DES_schedule,
@@ -748,7 +746,6 @@ static struct key_type keytype_des3 = {
     "des3",
     168,
     3 * sizeof(DES_cblock), 
-    3 * sizeof(DES_cblock), 
     3 * sizeof(DES_key_schedule), 
     DES3_random_key,
     DES3_schedule,
@@ -761,7 +758,6 @@ static struct key_type keytype_des3_derived = {
     "des3",
     168,
     3 * sizeof(DES_cblock),
-    3 * sizeof(DES_cblock),
     3 * sizeof(DES_key_schedule), 
     DES3_random_key,
     DES3_schedule,
@@ -774,7 +770,6 @@ static struct key_type keytype_aes128 = {
     "aes-128",
     128,
     16,
-    16,
     sizeof(struct krb5_aes_schedule),
     NULL,
     AES_schedule,
@@ -786,7 +781,6 @@ static struct key_type keytype_aes256 = {
     "aes-256",
     256,
     32,
-    32,
     sizeof(struct krb5_aes_schedule),
     NULL,
     AES_schedule,
@@ -798,7 +792,6 @@ static struct key_type keytype_arcfour = {
     "arcfour",
     128,
     16,
-    16,
     sizeof(RC4_KEY),
     NULL,
     ARCFOUR_schedule,
@@ -2450,6 +2443,58 @@ ARCFOUR_encrypt(krb5_context context,
 }
 
 
+/*
+ *
+ */
+
+static krb5_error_code
+AES_PRF(krb5_context context,
+       krb5_crypto crypto,
+       const krb5_data *in,
+       krb5_data *out)
+{
+    struct checksum_type *ct = crypto->et->checksum;
+    krb5_error_code ret;
+    Checksum result;
+    krb5_keyblock *derived;
+
+    result.cksumtype = ct->type;
+    ret = krb5_data_alloc(&result.checksum, ct->checksumsize);
+    if (ret) {
+       krb5_set_error_string(context, "out memory");
+       return ret;
+    }
+
+    (*ct->checksum)(context, NULL, in->data, in->length, 0, &result);
+
+    if (result.checksum.length < crypto->et->blocksize)
+       krb5_abortx(context, "internal prf error");
+
+    derived = NULL;
+    ret = krb5_derive_key(context, crypto->key.key, 
+                         crypto->et->type, "prf", 3, &derived);
+    if (ret)
+       krb5_abortx(context, "krb5_derive_key");
+
+    ret = krb5_data_alloc(out, crypto->et->blocksize);
+    if (ret)
+       krb5_abortx(context, "malloc failed");
+    
+    { 
+       AES_KEY key;
+
+       AES_set_encrypt_key(derived->keyvalue.data, 
+                           crypto->et->keytype->bits, &key);
+       AES_encrypt(result.checksum.data, out->data, &key);
+       memset(&key, 0, sizeof(key));
+    }
+
+    krb5_data_free(&result.checksum);
+    krb5_free_keyblock(context, derived);
+
+    return ret;
+}
+
 /*
  * these should currently be in reverse preference order.
  * (only relevant for !F_PSEUDO) */
@@ -2466,6 +2511,8 @@ static struct encryption_type enctype_null = {
     NULL,
     F_DISABLED,
     NULL_encrypt,
+    0,
+    NULL
 };
 static struct encryption_type enctype_des_cbc_crc = {
     ETYPE_DES_CBC_CRC,
@@ -2479,6 +2526,8 @@ static struct encryption_type enctype_des_cbc_crc = {
     NULL,
     0,
     DES_CBC_encrypt_key_ivec,
+    0,
+    NULL
 };
 static struct encryption_type enctype_des_cbc_md4 = {
     ETYPE_DES_CBC_MD4,
@@ -2492,6 +2541,8 @@ static struct encryption_type enctype_des_cbc_md4 = {
     &checksum_rsa_md4_des,
     0,
     DES_CBC_encrypt_null_ivec,
+    0,
+    NULL
 };
 static struct encryption_type enctype_des_cbc_md5 = {
     ETYPE_DES_CBC_MD5,
@@ -2505,6 +2556,8 @@ static struct encryption_type enctype_des_cbc_md5 = {
     &checksum_rsa_md5_des,
     0,
     DES_CBC_encrypt_null_ivec,
+    0,
+    NULL
 };
 static struct encryption_type enctype_arcfour_hmac_md5 = {
     ETYPE_ARCFOUR_HMAC_MD5,
@@ -2517,7 +2570,9 @@ static struct encryption_type enctype_arcfour_hmac_md5 = {
     &checksum_hmac_md5,
     NULL,
     F_SPECIAL,
-    ARCFOUR_encrypt
+    ARCFOUR_encrypt,
+    0,
+    NULL
 };
 static struct encryption_type enctype_des3_cbc_md5 = { 
     ETYPE_DES3_CBC_MD5,
@@ -2531,6 +2586,8 @@ static struct encryption_type enctype_des3_cbc_md5 = {
     &checksum_rsa_md5_des3,
     0,
     DES3_CBC_encrypt,
+    0,
+    NULL
 };
 static struct encryption_type enctype_des3_cbc_sha1 = {
     ETYPE_DES3_CBC_SHA1,
@@ -2544,6 +2601,8 @@ static struct encryption_type enctype_des3_cbc_sha1 = {
     &checksum_hmac_sha1_des3,
     F_DERIVED,
     DES3_CBC_encrypt,
+    0,
+    NULL
 };
 static struct encryption_type enctype_old_des3_cbc_sha1 = {
     ETYPE_OLD_DES3_CBC_SHA1,
@@ -2557,6 +2616,8 @@ static struct encryption_type enctype_old_des3_cbc_sha1 = {
     &checksum_hmac_sha1_des3,
     0,
     DES3_CBC_encrypt,
+    0,
+    NULL
 };
 static struct encryption_type enctype_aes128_cts_hmac_sha1 = {
     ETYPE_AES128_CTS_HMAC_SHA1_96,
@@ -2570,6 +2631,8 @@ static struct encryption_type enctype_aes128_cts_hmac_sha1 = {
     &checksum_hmac_sha1_aes128,
     F_DERIVED,
     AES_CTS_encrypt,
+    16,
+    AES_PRF
 };
 static struct encryption_type enctype_aes256_cts_hmac_sha1 = {
     ETYPE_AES256_CTS_HMAC_SHA1_96,
@@ -2583,6 +2646,8 @@ static struct encryption_type enctype_aes256_cts_hmac_sha1 = {
     &checksum_hmac_sha1_aes256,
     F_DERIVED,
     AES_CTS_encrypt,
+    16,
+    AES_PRF
 };
 static struct encryption_type enctype_des_cbc_none = {
     ETYPE_DES_CBC_NONE,
@@ -2596,6 +2661,8 @@ static struct encryption_type enctype_des_cbc_none = {
     NULL,
     F_PSEUDO,
     DES_CBC_encrypt_null_ivec,
+    0,
+    NULL
 };
 static struct encryption_type enctype_des_cfb64_none = {
     ETYPE_DES_CFB64_NONE,
@@ -2609,6 +2676,8 @@ static struct encryption_type enctype_des_cfb64_none = {
     NULL,
     F_PSEUDO,
     DES_CFB64_encrypt_null_ivec,
+    0,
+    NULL
 };
 static struct encryption_type enctype_des_pcbc_none = {
     ETYPE_DES_PCBC_NONE,
@@ -2622,6 +2691,8 @@ static struct encryption_type enctype_des_pcbc_none = {
     NULL,
     F_PSEUDO,
     DES_PCBC_encrypt_key_ivec,
+    0,
+    NULL
 };
 static struct encryption_type enctype_des3_cbc_none = {
     ETYPE_DES3_CBC_NONE,
@@ -2635,6 +2706,8 @@ static struct encryption_type enctype_des3_cbc_none = {
     NULL,
     F_PSEUDO,
     DES3_CBC_encrypt,
+    0,
+    NULL
 };
 
 static struct encryption_type *etypes[] = {
@@ -3090,8 +3163,8 @@ decrypt_internal_derived(krb5_context context,
     
     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
     if (len < checksum_sz) {
-       krb5_clear_error_string (context);
-       return EINVAL;          /* XXX - better error code? */
+       krb5_set_error_string(context, "Encrypted data shorter then checksum");
+       return KRB5_BAD_MSIZE;
     }
 
     if (((len - checksum_sz) % et->padsize) != 0) {
@@ -3357,11 +3430,8 @@ krb5_decrypt_EncryptedData(krb5_context context,
  *                                                          *
  ************************************************************/
 
-#ifdef HAVE_OPENSSL
-#include <openssl/rand.h>
+#define ENTROPY_NEEDED 128
 
-/* From openssl/crypto/rand/rand_lcl.h */
-#define ENTROPY_NEEDED 20
 static int
 seed_something(void)
 {
@@ -3417,7 +3487,8 @@ krb5_generate_random_block(void *buf, size_t len)
     HEIMDAL_MUTEX_lock(&crypto_mutex);
     if (!rng_initialized) {
        if (seed_something())
-           krb5_abortx(NULL, "Fatal: could not seed the random number generator");
+           krb5_abortx(NULL, "Fatal: could not seed the "
+                       "random number generator");
        
        rng_initialized = 1;
     }
@@ -3426,38 +3497,6 @@ krb5_generate_random_block(void *buf, size_t len)
        krb5_abortx(NULL, "Failed to generate random block");
 }
 
-#else
-
-void KRB5_LIB_FUNCTION
-krb5_generate_random_block(void *buf, size_t len)
-{
-    DES_cblock key, out;
-    static DES_cblock counter;
-    static DES_key_schedule schedule;
-    int i;
-    static int initialized = 0;
-
-    HEIMDAL_MUTEX_lock(&crypto_mutex);
-    if(!initialized) {
-       DES_new_random_key(&key);
-       DES_set_key(&key, &schedule);
-       memset(&key, 0, sizeof(key));
-       DES_new_random_key(&counter);
-       initialized = 1;
-    }
-    HEIMDAL_MUTEX_unlock(&crypto_mutex);
-    while(len > 0) {
-       DES_ecb_encrypt(&counter, &out, &schedule, DES_ENCRYPT);
-       for(i = 7; i >=0; i--)
-           if(counter[i]++)
-               break;
-       memcpy(buf, out, min(len, sizeof(out)));
-       len -= min(len, sizeof(out));
-       buf = (char*)buf + sizeof(out);
-    }
-}
-#endif
-
 static void
 DES3_postproc(krb5_context context,
              unsigned char *k, size_t len, struct key_data *key)
@@ -3645,7 +3684,7 @@ krb5_crypto_init(krb5_context context,
                               etype);
        return KRB5_PROG_ETYPE_NOSUPP;
     }
-    if((*crypto)->et->keytype->minsize > key->keyvalue.length) {
+    if((*crypto)->et->keytype->size != key->keyvalue.length) {
        free(*crypto);
        *crypto = NULL;
        krb5_set_error_string (context, "encryption key has bad length");
@@ -3844,6 +3883,50 @@ krb5_get_wrapped_length (krb5_context context,
        return wrapped_length (context, crypto, data_len);
 }
 
+/*
+ * Return the size of an encrypted packet of length `data_len'
+ */
+
+static size_t
+crypto_overhead (krb5_context context,
+                krb5_crypto  crypto)
+{
+    struct encryption_type *et = crypto->et;
+    size_t res;
+
+    res = CHECKSUMSIZE(et->checksum);
+    res += et->confoundersize;
+    if (et->padsize > 1)
+       res += et->padsize;
+    return res;
+}
+
+static size_t
+crypto_overhead_dervied (krb5_context context,
+                        krb5_crypto  crypto)
+{
+    struct encryption_type *et = crypto->et;
+    size_t res;
+
+    if (et->keyed_checksum)
+       res = CHECKSUMSIZE(et->keyed_checksum);
+    else
+       res = CHECKSUMSIZE(et->checksum);
+    res += et->confoundersize;
+    if (et->padsize > 1)
+       res += et->padsize;
+    return res;
+}
+
+size_t
+krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
+{
+    if (derived_crypto (context, crypto))
+       return crypto_overhead_dervied (context, crypto);
+    else
+       return crypto_overhead (context, crypto);
+}
+
 krb5_error_code KRB5_LIB_FUNCTION
 krb5_random_to_key(krb5_context context,
                   krb5_enctype type,
@@ -3934,6 +4017,44 @@ _krb5_pk_octetstring2key(krb5_context context,
     return ret;
 }
 
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_prf_length(krb5_context context,
+                      krb5_enctype type,
+                      size_t *length)
+{
+    struct encryption_type *et = _find_enctype(type);
+
+    if(et == NULL || et->prf_length == 0) {
+       krb5_set_error_string(context, "encryption type %d not supported",
+                             type);
+       return KRB5_PROG_ETYPE_NOSUPP;
+    }
+
+    *length = et->prf_length;
+    return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_prf(krb5_context context,
+               const krb5_crypto crypto,
+               const krb5_data *input, 
+               krb5_data *output)
+{
+    struct encryption_type *et = crypto->et;
+
+    krb5_data_zero(output);
+
+    if(et->prf == NULL) {
+       krb5_set_error_string(context, "kerberos prf for %s not supported",
+                             et->name);
+       return KRB5_PROG_ETYPE_NOSUPP;
+    }
+
+    return (*et->prf)(context, crypto, input, output);
+}
+       
+
+
 
 #ifdef CRYPTO_DEBUG