+Tue Jan 5 00:09:13 1999 Tom Yu <tlyu@mit.edu>
+
+ * dk.h: Add prototypes for krb5_marc_dk_*.
+
+ * dk_encrypt.c (krb5_marc_dk_encrypt): Add compat for 32-bit
+ length coded ciphertext.
+
+ * dk_decrypt.c (krb5_marc_dk_decrypt): Add compat for 32-bit
+ length coded ciphertext.
+
+ * checksum.c: Add compat for 32-bit length included checksum.
+ Note that nothing uses this at the moment, and probably
+ shouldn't.
+
1998-11-13 Theodore Ts'o <tytso@rsts-11.mit.edu>
* Makefile.in: Set the myfulldir and mydir variables (which are
return(ret);
}
+
+#ifdef ATHENA_DES3_KLUDGE
+krb5_error_code
+krb5_marc_dk_make_checksum(hash, key, usage, input, output)
+ krb5_const struct krb5_hash_provider *hash;
+ krb5_const krb5_keyblock *key;
+ krb5_keyusage usage;
+ krb5_const krb5_data *input;
+ krb5_data *output;
+{
+ int i;
+ struct krb5_enc_provider *enc;
+ size_t blocksize, keybytes, keylength;
+ krb5_error_code ret;
+ unsigned char constantdata[K5CLENGTH];
+ krb5_data datain[2];
+ unsigned char *kcdata;
+ krb5_keyblock kc;
+
+ for (i=0; i<krb5_enctypes_length; i++) {
+ if (krb5_enctypes_list[i].etype == key->enctype)
+ break;
+ }
+
+ if (i == krb5_enctypes_length)
+ return(KRB5_BAD_ENCTYPE);
+
+ enc = krb5_enctypes_list[i].enc;
+
+ /* allocate and set to-be-derived keys */
+
+ (*(enc->block_size))(&blocksize);
+ (*(enc->keysize))(&keybytes, &keylength);
+
+ /* key->length will be tested in enc->encrypt
+ output->length will be tested in krb5_hmac */
+
+ if ((kcdata = (unsigned char *) malloc(keylength)) == NULL)
+ return(ENOMEM);
+
+ kc.contents = kcdata;
+ kc.length = keylength;
+
+ /* derive the key */
+
+ datain[0].data = constantdata;
+ datain[0].length = K5CLENGTH;
+
+ datain[0].data[0] = (usage>>24)&0xff;
+ datain[0].data[1] = (usage>>16)&0xff;
+ datain[0].data[2] = (usage>>8)&0xff;
+ datain[0].data[3] = usage&0xff;
+
+ datain[0].data[4] = 0x99;
+
+ if (ret = krb5_derive_key(enc, key, &kc, &datain[0]))
+ goto cleanup;
+
+ /* hash the data */
+
+ datain[0].length = 4;
+ datain[0].data[0] = (input->length>>24)&0xff;
+ datain[0].data[1] = (input->length>>16)&0xff;
+ datain[0].data[2] = (input->length>>8)&0xff;
+ datain[0].data[3] = input->length&0xff;
+
+ datain[1] = *input;
+
+ if (ret = krb5_hmac(hash, &kc, 2, datain, output))
+ memset(output->data, 0, output->length);
+
+ /* ret is set correctly by the prior call */
+
+cleanup:
+ memset(kcdata, 0, keylength);
+
+ free(kcdata);
+
+ return(ret);
+}
+#endif /* ATHENA_DES3_KLUDGE */
KRB5_PROTOTYPE((krb5_const struct krb5_hash_provider *hash,
krb5_const krb5_keyblock *key, krb5_keyusage usage,
krb5_const krb5_data *input, krb5_data *output));
+
+#ifdef ATHENA_DES3_KLUDGE
+void krb5_marc_dk_encrypt_length
+KRB5_PROTOTYPE((krb5_const struct krb5_enc_provider *enc,
+ krb5_const struct krb5_hash_provider *hash,
+ size_t input, size_t *length));
+
+krb5_error_code krb5_marc_dk_encrypt
+KRB5_PROTOTYPE((krb5_const struct krb5_enc_provider *enc,
+ krb5_const struct krb5_hash_provider *hash,
+ krb5_const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_const krb5_data *ivec,
+ krb5_const krb5_data *input, krb5_data *output));
+
+krb5_error_code krb5_marc_dk_decrypt
+KRB5_PROTOTYPE((krb5_const struct krb5_enc_provider *enc,
+ krb5_const struct krb5_hash_provider *hash,
+ krb5_const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_const krb5_data *ivec, krb5_const krb5_data *input,
+ krb5_data *arg_output));
+
+krb5_error_code krb5_marc_dk_make_checksum
+KRB5_PROTOTYPE((krb5_const struct krb5_hash_provider *hash,
+ krb5_const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_const krb5_data *input, krb5_data *output));
+#endif /* ATHENA_DES3_KLUDGE */
return(ret);
}
+
+#ifdef ATHENA_DES3_KLUDGE
+krb5_error_code
+krb5_marc_dk_decrypt(enc, hash, key, usage, ivec, input, output)
+ krb5_const struct krb5_enc_provider *enc;
+ krb5_const struct krb5_hash_provider *hash;
+ krb5_const krb5_keyblock *key;
+ krb5_keyusage usage;
+ krb5_const krb5_data *ivec;
+ krb5_const krb5_data *input;
+ krb5_data *output;
+{
+ krb5_error_code ret;
+ size_t hashsize, blocksize, keybytes, keylength, enclen, plainlen;
+ unsigned char *plaindata, *kedata, *kidata, *cksum;
+ krb5_keyblock ke, ki;
+ krb5_data d1, d2;
+ unsigned char constantdata[K5CLENGTH];
+
+ /* allocate and set up ciphertext and to-be-derived keys */
+
+ (*(hash->hash_size))(&hashsize);
+ (*(enc->block_size))(&blocksize);
+ (*(enc->keysize))(&keybytes, &keylength);
+
+ enclen = input->length - hashsize;
+
+ if ((kedata = (unsigned char *) malloc(keylength)) == NULL)
+ return(ENOMEM);
+ if ((kidata = (unsigned char *) malloc(keylength)) == NULL) {
+ free(kedata);
+ return(ENOMEM);
+ }
+ if ((plaindata = (unsigned char *) malloc(enclen)) == NULL) {
+ free(kidata);
+ free(kedata);
+ return(ENOMEM);
+ }
+ if ((cksum = (unsigned char *) malloc(hashsize)) == NULL) {
+ free(plaindata);
+ free(kidata);
+ free(kedata);
+ return(ENOMEM);
+ }
+
+ ke.contents = kedata;
+ ke.length = keylength;
+ ki.contents = kidata;
+ ki.length = keylength;
+
+ /* derive the keys */
+
+ d1.data = constantdata;
+ d1.length = K5CLENGTH;
+
+ d1.data[0] = (usage>>24)&0xff;
+ d1.data[1] = (usage>>16)&0xff;
+ d1.data[2] = (usage>>8)&0xff;
+ d1.data[3] = usage&0xff;
+
+ d1.data[4] = 0xAA;
+
+ if (ret = krb5_derive_key(enc, key, &ke, &d1))
+ goto cleanup;
+
+ d1.data[4] = 0x55;
+
+ if (ret = krb5_derive_key(enc, key, &ki, &d1))
+ goto cleanup;
+
+ /* decrypt the ciphertext */
+
+ d1.length = enclen;
+ d1.data = input->data;
+
+ d2.length = enclen;
+ d2.data = plaindata;
+
+ if (ret = ((*(enc->decrypt))(&ke, ivec, &d1, &d2)))
+ goto cleanup;
+
+ /* verify the hash */
+
+ d1.length = hashsize;
+ d1.data = cksum;
+
+ if (ret = krb5_hmac(hash, &ki, 1, &d2, &d1))
+ goto cleanup;
+
+ if (memcmp(cksum, input->data+enclen, hashsize) != 0) {
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ goto cleanup;
+ }
+
+ /* because this encoding isn't self-describing wrt length, the
+ best we can do here is to compute the length minus the
+ confounder. */
+
+ /* get the real plaintext length and copy the data into the output */
+
+ plainlen = ((((plaindata+blocksize)[0])<<24) |
+ (((plaindata+blocksize)[1])<<16) |
+ (((plaindata+blocksize)[2])<<8) |
+ ((plaindata+blocksize)[3]));
+
+ if (plainlen > (enclen - blocksize - 4))
+ return(KRB5_BAD_MSIZE);
+
+ if (output->length < plainlen)
+ return(KRB5_BAD_MSIZE);
+
+ output->length = plainlen;
+
+ memcpy(output->data, d2.data+4+blocksize, output->length);
+
+ ret = 0;
+
+cleanup:
+ memset(kedata, 0, keylength);
+ memset(kidata, 0, keylength);
+ memset(plaindata, 0, enclen);
+ memset(cksum, 0, hashsize);
+
+ free(cksum);
+ free(plaindata);
+ free(kidata);
+ free(kedata);
+
+ return(ret);
+}
+#endif /* ATHENA_DES3_KLUDGE */
return(ret);
}
+
+#ifdef ATHENA_DES3_KLUDGE
+void
+krb5_marc_dk_encrypt_length(enc, hash, inputlen, length)
+ krb5_const struct krb5_enc_provider *enc;
+ krb5_const struct krb5_hash_provider *hash;
+ size_t inputlen;
+ size_t *length;
+{
+ size_t blocksize, hashsize;
+
+ (*(enc->block_size))(&blocksize);
+ (*(hash->hash_size))(&hashsize);
+
+ *length = krb5_roundup(blocksize+4+inputlen, blocksize) + hashsize;
+}
+
+krb5_error_code
+krb5_marc_dk_encrypt(enc, hash, key, usage, ivec, input, output)
+ krb5_const struct krb5_enc_provider *enc;
+ krb5_const struct krb5_hash_provider *hash;
+ krb5_const krb5_keyblock *key;
+ krb5_keyusage usage;
+ krb5_const krb5_data *ivec;
+ krb5_const krb5_data *input;
+ krb5_data *output;
+{
+ size_t blocksize, keybytes, keylength, plainlen, enclen;
+ krb5_error_code ret;
+ unsigned char constantdata[K5CLENGTH];
+ krb5_data d1, d2;
+ unsigned char *plaintext, *kedata, *kidata;
+ krb5_keyblock ke, ki;
+
+ /* allocate and set up plaintext and to-be-derived keys */
+
+ (*(enc->block_size))(&blocksize);
+ (*(enc->keysize))(&keybytes, &keylength);
+ plainlen = krb5_roundup(blocksize+4+input->length, blocksize);
+
+ krb5_dk_encrypt_length(enc, hash, input->length, &enclen);
+
+ /* key->length, ivec will be tested in enc->encrypt */
+
+ if (output->length < enclen)
+ return(KRB5_BAD_MSIZE);
+
+ if ((kedata = (unsigned char *) malloc(keylength)) == NULL)
+ return(ENOMEM);
+ if ((kidata = (unsigned char *) malloc(keylength)) == NULL) {
+ free(kedata);
+ return(ENOMEM);
+ }
+ if ((plaintext = (unsigned char *) malloc(plainlen)) == NULL) {
+ free(kidata);
+ free(kedata);
+ return(ENOMEM);
+ }
+
+ ke.contents = kedata;
+ ke.length = keylength;
+ ki.contents = kidata;
+ ki.length = keylength;
+
+ /* derive the keys */
+
+ d1.data = constantdata;
+ d1.length = K5CLENGTH;
+
+ d1.data[0] = (usage>>24)&0xff;
+ d1.data[1] = (usage>>16)&0xff;
+ d1.data[2] = (usage>>8)&0xff;
+ d1.data[3] = usage&0xff;
+
+ d1.data[4] = 0xAA;
+
+ if (ret = krb5_derive_key(enc, key, &ke, &d1))
+ goto cleanup;
+
+ d1.data[4] = 0x55;
+
+ if (ret = krb5_derive_key(enc, key, &ki, &d1))
+ goto cleanup;
+
+ /* put together the plaintext */
+
+ d1.length = blocksize;
+ d1.data = plaintext;
+
+ if (ret = krb5_c_random_make_octets(/* XXX */ 0, &d1))
+ goto cleanup;
+
+ (plaintext+blocksize)[0] = (input->length>>24)&0xff;
+ (plaintext+blocksize)[1] = (input->length>>16)&0xff;
+ (plaintext+blocksize)[2] = (input->length>>8)&0xff;
+ (plaintext+blocksize)[3] = input->length&0xff;
+
+ memcpy(plaintext+blocksize+4, input->data, input->length);
+
+ memset(plaintext+blocksize+4+input->length, 0,
+ plainlen - (blocksize+4+input->length));
+
+ /* encrypt the plaintext */
+
+ d1.length = plainlen;
+ d1.data = plaintext;
+
+ d2.length = plainlen;
+ d2.data = output->data;
+
+ if (ret = ((*(enc->encrypt))(&ke, ivec, &d1, &d2)))
+ goto cleanup;
+
+ /* hash the plaintext */
+
+ d2.length = enclen - plainlen;
+ d2.data = output->data+plainlen;
+
+ output->length = enclen;
+
+ if (ret = krb5_hmac(hash, &ki, 1, &d1, &d2))
+ memset(d2.data, 0, d2.length);
+
+ /* ret is set correctly by the prior call */
+
+cleanup:
+ memset(kedata, 0, keylength);
+ memset(kidata, 0, keylength);
+ memset(plaintext, 0, plainlen);
+
+ free(plaintext);
+ free(kidata);
+ free(kedata);
+
+ return(ret);
+}
+#endif /* ATHENA_DES3_KLUDGE */