From 574d3785ab3d463dadb2347e9c4d386be93eee84 Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Sat, 18 Sep 2004 03:59:51 +0000
Subject: [PATCH] Add extra checks for keys and convenience encrypt/decrypt
 functions

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3803 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 include/asterisk/crypto.h | 23 +++++++++++++
 res/res_crypto.c          | 71 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 86 insertions(+), 8 deletions(-)

diff --git a/include/asterisk/crypto.h b/include/asterisk/crypto.h
index 227957a9b0..dff70e6b04 100755
--- a/include/asterisk/crypto.h
+++ b/include/asterisk/crypto.h
@@ -85,6 +85,29 @@ extern int ast_sign(struct ast_key *key, char *msg, char *sig);
  */
 extern int ast_sign_bin(struct ast_key *key, char *msg, int msglen, unsigned char *sig);
 
+/*!
+ * \param key a private key to use to encrypt
+ * \param src the message to encrypt
+ * \param srclen the length of the message to encrypt
+ * \param dst a pointer to a buffer of at least srclen * 1.5 bytes in which the encrypted
+ * answer will be stored
+ *
+ * Returns length of encrypted data on success or -1 on failure.
+ *
+ */
+extern int ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
+
+/*!
+ * \param key a private key to use to decrypt
+ * \param src the message to decrypt
+ * \param srclen the length of the message to decrypt
+ * \param dst a pointer to a buffer of at least srclen bytes in which the decrypted
+ * answer will be stored
+ *
+ * Returns length of decrypted data on success or -1 on failure.
+ *
+ */
+extern int ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/res/res_crypto.c b/res/res_crypto.c
index 9da1c48b1e..6152d42b09 100755
--- a/res/res_crypto.c
+++ b/res/res_crypto.c
@@ -233,13 +233,16 @@ static struct ast_key *try_load_key (char *dir, char *fname, int ifd, int ofd, i
 		key->rsa = PEM_read_RSAPrivateKey(f, NULL, pw_cb, key);
 	fclose(f);
 	if (key->rsa) {
-		/* Key loaded okay */
-		key->ktype &= ~KEY_NEEDS_PASSCODE;
-		if (option_verbose > 2)
-			ast_verbose(VERBOSE_PREFIX_3 "Loaded %s key '%s'\n", key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
-		if (option_debug)
-			ast_log(LOG_DEBUG, "Key '%s' loaded OK\n", key->name);
-		key->delme = 0;
+		if (RSA_size(key->rsa) == 128) {
+			/* Key loaded okay */
+			key->ktype &= ~KEY_NEEDS_PASSCODE;
+			if (option_verbose > 2)
+				ast_verbose(VERBOSE_PREFIX_3 "Loaded %s key '%s'\n", key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
+			if (option_debug)
+				ast_log(LOG_DEBUG, "Key '%s' loaded OK\n", key->name);
+			key->delme = 0;
+		} else
+			ast_log(LOG_NOTICE, "Key '%s' is not expected size.\n", key->name);
 	} else if (key->infd != -2) {
 		ast_log(LOG_WARNING, "Key load %s '%s' failed\n",key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
 		if (ofd > -1) {
@@ -303,7 +306,7 @@ int ast_sign_bin(struct ast_key *key, char *msg, int msglen, unsigned char *dsig
 	int res;
 
 	if (key->ktype != AST_KEY_PRIVATE) {
-		ast_log(LOG_WARNING, "Cannot sign with a private key\n");
+		ast_log(LOG_WARNING, "Cannot sign with a public key\n");
 		return -1;
 	}
 
@@ -327,6 +330,58 @@ int ast_sign_bin(struct ast_key *key, char *msg, int msglen, unsigned char *dsig
 	
 }
 
+extern int ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
+{
+	int res;
+	int pos = 0;
+	if (key->ktype != AST_KEY_PRIVATE) {
+		ast_log(LOG_WARNING, "Cannot decrypt with a public key\n");
+		return -1;
+	}
+
+	if (srclen % 128) {
+		ast_log(LOG_NOTICE, "Tried to decrypt something not a multiple of 128 bytes\n");
+		return -1;
+	}
+	while(srclen) {
+		/* Process chunks 128 bytes at a time */
+		res = RSA_private_decrypt(128, src, dst, key->rsa, RSA_PKCS1_OAEP_PADDING);
+		if (res < 0)
+			return -1;
+		pos += res;
+		src += 128;
+		srclen -= 128;
+		dst += res;
+	}
+	return pos;
+}
+
+extern int ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
+{
+	int res;
+	int bytes;
+	int pos = 0;
+	if (key->ktype != AST_KEY_PUBLIC) {
+		ast_log(LOG_WARNING, "Cannot encrypt with a private key\n");
+		return -1;
+	}
+	
+	while(srclen) {
+		bytes = srclen;
+		if (bytes > 128 - 41)
+			bytes = 128 - 41;
+		/* Process chunks 128 bytes at a time */
+		res = RSA_private_encrypt(bytes, src, dst, key->rsa, RSA_PKCS1_OAEP_PADDING);
+		if (res != 128)
+			return -1;
+		src += 128 - 41;
+		srclen -= 128 - 41;
+		pos += res;
+		dst += res;
+	}
+	return pos;
+}
+
 int ast_sign(struct ast_key *key, char *msg, char *sig)
 {
 	unsigned char dsig[128];
-- 
GitLab