summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyexchange/isakmpd-20041012/crypto.c')
-rw-r--r--keyexchange/isakmpd-20041012/crypto.c413
1 files changed, 413 insertions, 0 deletions
diff --git a/keyexchange/isakmpd-20041012/crypto.c b/keyexchange/isakmpd-20041012/crypto.c
new file mode 100644
index 0000000..d74191e
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/crypto.c
@@ -0,0 +1,413 @@
+/* $OpenBSD: crypto.c,v 1.22 2004/06/14 09:55:41 ho Exp $ */
+/* $EOM: crypto.c,v 1.32 2000/03/07 20:08:51 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdep.h"
+
+#include "crypto.h"
+#include "log.h"
+
+enum cryptoerr des1_init(struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr des3_init(struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr blf_init(struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr cast_init(struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr aes_init(struct keystate *, u_int8_t *, u_int16_t);
+void des1_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void des1_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+void des3_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void des3_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+void blf_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void blf_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+void cast1_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void cast1_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+void aes_encrypt(struct keystate *, u_int8_t *, u_int16_t);
+void aes_decrypt(struct keystate *, u_int8_t *, u_int16_t);
+
+struct crypto_xf transforms[] = {
+#ifdef USE_DES
+ {
+ DES_CBC, "Data Encryption Standard (CBC-Mode)", 8, 8,
+ BLOCKSIZE, 0,
+ des1_init,
+ des1_encrypt, des1_decrypt
+ },
+#endif
+#ifdef USE_TRIPLEDES
+ {
+ TRIPLEDES_CBC, "Triple-DES (CBC-Mode)", 24, 24,
+ BLOCKSIZE, 0,
+ des3_init,
+ des3_encrypt, des3_decrypt
+ },
+#endif
+#ifdef USE_BLOWFISH
+ {
+ BLOWFISH_CBC, "Blowfish (CBC-Mode)", 12, 56,
+ BLOCKSIZE, 0,
+ blf_init,
+ blf_encrypt, blf_decrypt
+ },
+#endif
+#ifdef USE_CAST
+ {
+ CAST_CBC, "CAST (CBC-Mode)", 12, 16,
+ BLOCKSIZE, 0,
+ cast_init,
+ cast1_encrypt, cast1_decrypt
+ },
+#endif
+#ifdef USE_AES
+ {
+ AES_CBC, "AES (CBC-Mode)", 16, 32,
+ AES_BLOCK_SIZE, 0,
+ aes_init,
+ aes_encrypt, aes_decrypt
+ },
+#endif
+};
+
+/* Hmm, the function prototypes for des are really dumb */
+#ifdef __OpenBSD__
+#define DC (des_cblock *)
+#else
+#define DC (void *)
+#endif
+
+enum cryptoerr
+des1_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ /* des_set_key returns -1 for parity problems, and -2 for weak keys */
+ des_set_odd_parity(DC key);
+ switch (des_set_key(DC key, ks->ks_des[0])) {
+ case -2:
+ return EWEAKKEY;
+ default:
+ return EOKAY;
+ }
+}
+
+void
+des1_encrypt(struct keystate *ks, u_int8_t *d, u_int16_t len)
+{
+ des_cbc_encrypt(DC d, DC d, len, ks->ks_des[0], DC ks->riv,
+ DES_ENCRYPT);
+}
+
+void
+des1_decrypt(struct keystate *ks, u_int8_t *d, u_int16_t len)
+{
+ des_cbc_encrypt(DC d, DC d, len, ks->ks_des[0], DC ks->riv,
+ DES_DECRYPT);
+}
+
+#ifdef USE_TRIPLEDES
+enum cryptoerr
+des3_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ des_set_odd_parity(DC key);
+ des_set_odd_parity(DC(key + 8));
+ des_set_odd_parity(DC(key + 16));
+
+ /* As of the draft Tripe-DES does not check for weak keys */
+ des_set_key(DC key, ks->ks_des[0]);
+ des_set_key(DC(key + 8), ks->ks_des[1]);
+ des_set_key(DC(key + 16), ks->ks_des[2]);
+
+ return EOKAY;
+}
+
+void
+des3_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy(iv, ks->riv, ks->xf->blocksize);
+ des_ede3_cbc_encrypt(DC data, DC data, len, ks->ks_des[0],
+ ks->ks_des[1], ks->ks_des[2], DC iv, DES_ENCRYPT);
+}
+
+void
+des3_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy(iv, ks->riv, ks->xf->blocksize);
+ des_ede3_cbc_encrypt(DC data, DC data, len, ks->ks_des[0],
+ ks->ks_des[1], ks->ks_des[2], DC iv, DES_DECRYPT);
+}
+#undef DC
+#endif /* USE_TRIPLEDES */
+
+#ifdef USE_BLOWFISH
+enum cryptoerr
+blf_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ blf_key(&ks->ks_blf, key, len);
+
+ return EOKAY;
+}
+
+void
+blf_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int8_t *iv = ks->liv;
+ u_int32_t xl, xr;
+
+ memcpy(iv, ks->riv, blocksize);
+
+ for (i = 0; i < len; data += blocksize, i += blocksize) {
+ XOR64(data, iv);
+ xl = GET_32BIT_BIG(data);
+ xr = GET_32BIT_BIG(data + 4);
+ Blowfish_encipher(&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG(data, xl);
+ SET_32BIT_BIG(data + 4, xr);
+ SET64(iv, data);
+ }
+}
+
+void
+blf_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int32_t xl, xr;
+
+ data += len - blocksize;
+ for (i = len - blocksize; i >= blocksize; data -= blocksize,
+ i -= blocksize) {
+ xl = GET_32BIT_BIG(data);
+ xr = GET_32BIT_BIG(data + 4);
+ Blowfish_decipher(&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG(data, xl);
+ SET_32BIT_BIG(data + 4, xr);
+ XOR64(data, data - blocksize);
+
+ }
+ xl = GET_32BIT_BIG(data);
+ xr = GET_32BIT_BIG(data + 4);
+ Blowfish_decipher(&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG(data, xl);
+ SET_32BIT_BIG(data + 4, xr);
+ XOR64(data, ks->riv);
+}
+#endif /* USE_BLOWFISH */
+
+#ifdef USE_CAST
+enum cryptoerr
+cast_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ cast_setkey(&ks->ks_cast, key, len);
+ return EOKAY;
+}
+
+void
+cast1_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int8_t *iv = ks->liv;
+
+ memcpy(iv, ks->riv, blocksize);
+
+ for (i = 0; i < len; data += blocksize, i += blocksize) {
+ XOR64(data, iv);
+ cast_encrypt(&ks->ks_cast, data, data);
+ SET64(iv, data);
+ }
+}
+
+void
+cast1_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+
+ data += len - blocksize;
+ for (i = len - blocksize; i >= blocksize; data -= blocksize,
+ i -= blocksize) {
+ cast_decrypt(&ks->ks_cast, data, data);
+ XOR64(data, data - blocksize);
+ }
+ cast_decrypt(&ks->ks_cast, data, data);
+ XOR64(data, ks->riv);
+}
+#endif /* USE_CAST */
+
+#ifdef USE_AES
+enum cryptoerr
+aes_init(struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ AES_set_encrypt_key(key, len << 3, &ks->ks_aes[0]);
+ AES_set_decrypt_key(key, len << 3, &ks->ks_aes[1]);
+ return EOKAY;
+}
+
+void
+aes_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy(iv, ks->riv, ks->xf->blocksize);
+ AES_cbc_encrypt(data, data, len, &ks->ks_aes[0], iv, AES_ENCRYPT);
+}
+
+void
+aes_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy(iv, ks->riv, ks->xf->blocksize);
+ AES_cbc_encrypt(data, data, len, &ks->ks_aes[1], iv, AES_DECRYPT);
+}
+#endif /* USE_AES */
+
+struct crypto_xf *
+crypto_get(enum transform id)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof transforms / sizeof transforms[0]; i++)
+ if (id == transforms[i].id)
+ return &transforms[i];
+
+ return 0;
+}
+
+struct keystate *
+crypto_init(struct crypto_xf *xf, u_int8_t *key, u_int16_t len,
+ enum cryptoerr *err)
+{
+ struct keystate *ks;
+
+ if (len < xf->keymin || len > xf->keymax) {
+ LOG_DBG((LOG_CRYPTO, 10, "crypto_init: invalid key length %d",
+ len));
+ *err = EKEYLEN;
+ return 0;
+ }
+ ks = calloc(1, sizeof *ks);
+ if (!ks) {
+ log_error("crypto_init: calloc (1, %lu) failed",
+ (unsigned long)sizeof *ks);
+ *err = ENOCRYPTO;
+ return 0;
+ }
+ ks->xf = xf;
+
+ /* Setup the IV. */
+ ks->riv = ks->iv;
+ ks->liv = ks->iv2;
+
+ LOG_DBG_BUF((LOG_CRYPTO, 40, "crypto_init: key", key, len));
+
+ *err = xf->init(ks, key, len);
+ if (*err != EOKAY) {
+ LOG_DBG((LOG_CRYPTO, 30, "crypto_init: weak key found for %s",
+ xf->name));
+ free(ks);
+ return 0;
+ }
+ return ks;
+}
+
+void
+crypto_update_iv(struct keystate *ks)
+{
+ u_int8_t *tmp;
+
+ tmp = ks->riv;
+ ks->riv = ks->liv;
+ ks->liv = tmp;
+
+ LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_update_iv: updated IV", ks->riv,
+ ks->xf->blocksize));
+}
+
+void
+crypto_init_iv(struct keystate *ks, u_int8_t *buf, size_t len)
+{
+ memcpy(ks->riv, buf, len);
+
+ LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_init_iv: initialized IV", ks->riv,
+ len));
+}
+
+void
+crypto_encrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len)
+{
+ LOG_DBG_BUF((LOG_CRYPTO, 10, "crypto_encrypt: before encryption", buf,
+ len));
+ ks->xf->encrypt(ks, buf, len);
+ memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize);
+ LOG_DBG_BUF((LOG_CRYPTO, 30, "crypto_encrypt: after encryption", buf,
+ len));
+}
+
+void
+crypto_decrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len)
+{
+ LOG_DBG_BUF((LOG_CRYPTO, 10, "crypto_decrypt: before decryption", buf,
+ len));
+ /*
+ * XXX There is controversy about the correctness of updating the IV
+ * like this.
+ */
+ memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize);
+ ks->xf->decrypt(ks, buf, len);
+ LOG_DBG_BUF((LOG_CRYPTO, 30, "crypto_decrypt: after decryption", buf,
+ len));
+}
+
+/* Make a copy of the keystate pointed to by OKS. */
+struct keystate *
+crypto_clone_keystate(struct keystate *oks)
+{
+ struct keystate *ks;
+
+ ks = malloc(sizeof *ks);
+ if (!ks) {
+ log_error("crypto_clone_keystate: malloc (%lu) failed",
+ (unsigned long)sizeof *ks);
+ return 0;
+ }
+ memcpy(ks, oks, sizeof *ks);
+ if (oks->riv == oks->iv) {
+ ks->riv = ks->iv;
+ ks->liv = ks->iv2;
+ } else {
+ ks->riv = ks->iv2;
+ ks->liv = ks->iv;
+ }
+ return ks;
+}