+ Cipher *c;
+ if (name == NULL)
+ return -1;
+ c = cipher_by_name(name);
+ return (c==NULL) ? -1 : c->number;
+}
+
+char *
+cipher_name(int id)
+{
+ Cipher *c = cipher_by_number(id);
+ return (c==NULL) ? "<unknown>" : c->name;
+}
+
+void
+cipher_init(CipherContext *cc, Cipher *cipher,
+ const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
+ int encrypt)
+{
+ static int dowarn = 1;
+#ifdef SSH_OLD_EVP
+ EVP_CIPHER *type;
+#else
+ const EVP_CIPHER *type;
+#endif
+ int klen;
+
+ if (cipher->number == SSH_CIPHER_DES) {
+ if (dowarn) {
+ error("Warning: use of DES is strongly discouraged "
+ "due to cryptographic weaknesses");
+ dowarn = 0;
+ }
+ if (keylen > 8)
+ keylen = 8;
+ }
+ cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
+
+ if (keylen < cipher->key_len)
+ fatal("cipher_init: key length %d is insufficient for %s.",
+ keylen, cipher->name);
+ if (iv != NULL && ivlen < cipher->block_size)
+ fatal("cipher_init: iv length %d is insufficient for %s.",
+ ivlen, cipher->name);
+ cc->cipher = cipher;
+
+ type = (*cipher->evptype)();
+
+ EVP_CIPHER_CTX_init(&cc->evp);
+#ifdef SSH_OLD_EVP
+ if (type->key_len > 0 && type->key_len != keylen) {
+ debug("cipher_init: set keylen (%d -> %d)",
+ type->key_len, keylen);
+ type->key_len = keylen;
+ }
+ EVP_CipherInit(&cc->evp, type, (u_char *)key, (u_char *)iv,
+ (encrypt == CIPHER_ENCRYPT));
+#else
+ if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
+ (encrypt == CIPHER_ENCRYPT)) == 0)
+ fatal("cipher_init: EVP_CipherInit failed for %s",
+ cipher->name);
+ klen = EVP_CIPHER_CTX_key_length(&cc->evp);
+ if (klen > 0 && keylen != klen) {
+ debug2("cipher_init: set keylen (%d -> %d)", klen, keylen);
+ if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0)
+ fatal("cipher_init: set keylen failed (%d -> %d)",
+ klen, keylen);
+ }
+ if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0)
+ fatal("cipher_init: EVP_CipherInit: set key failed for %s",
+ cipher->name);
+#endif
+}
+
+void
+cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+{
+ if (len % cc->cipher->block_size)
+ fatal("cipher_encrypt: bad plaintext length %d", len);
+#ifdef SSH_OLD_EVP
+ EVP_Cipher(&cc->evp, dest, (u_char *)src, len);
+#else
+ if (EVP_Cipher(&cc->evp, dest, (u_char *)src, len) == 0)
+ fatal("evp_crypt: EVP_Cipher failed");
+#endif
+}
+
+void
+cipher_cleanup(CipherContext *cc)
+{
+#ifdef SSH_OLD_EVP
+ EVP_CIPHER_CTX_cleanup(&cc->evp);
+#else
+ if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
+ error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed");
+#endif