[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] Add helpful hybrid encryption functions
Update of /home/or/cvsroot/src/common
In directory moria.mit.edu:/tmp/cvs-serv11980/src/common
Modified Files:
crypto.c crypto.h
Log Message:
Add helpful hybrid encryption functions
Index: crypto.c
===================================================================
RCS file: /home/or/cvsroot/src/common/crypto.c,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -d -r1.62 -r1.63
--- crypto.c 31 Mar 2004 22:41:25 -0000 1.62
+++ crypto.c 1 Apr 2004 03:08:34 -0000 1.63
@@ -114,6 +114,17 @@
}
}
+static INLINE int
+crypto_get_rsa_padding_overhead(int padding) {
+ switch(padding)
+ {
+ case RSA_NO_PADDING: return 0;
+ case RSA_PKCS1_OAEP_PADDING: return 42;
+ case RSA_PKCS1_PADDING: return 11;
+ default: assert(0); return -1;
+ }
+}
+
static int _crypto_global_initialized = 0;
int crypto_global_init()
@@ -645,6 +656,118 @@
}
}
+/* Perform a hybrid (public/secret) encryption on 'fromlen' bytes of data
+ * from 'from', with padding type 'padding', storing the results on 'to'.
+ *
+ * If no padding is used, the public key must be at least as large as
+ * 'from'.
+ *
+ * Returns the number of bytes written on success, -1 on failure.
+ *
+ * The encrypted data consists of:
+ *
+ * The source data, padded and encrypted with the public key, if the
+ * padded source data is no longer than the public key.
+ * OR
+ * The beginning of the source data prefixed with a 16-symmetric key,
+ * padded and encrypted with the public key; followed by the rest of
+ * the source data encrypted in AES-CTR mode with the symmetric key.
+ */
+int crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, unsigned char *from,
+ int fromlen, unsigned char *to,
+ int padding)
+{
+ int overhead, pkeylen, outlen, r, symlen;
+ crypto_cipher_env_t *cipher = NULL;
+ char buf[1024];
+
+ assert(env && from && to);
+
+ overhead = crypto_get_rsa_padding_overhead(padding);
+ pkeylen = crypto_pk_keysize(env);
+
+ if (padding == RSA_NO_PADDING && fromlen < pkeylen)
+ return -1;
+
+ if (fromlen+overhead <= pkeylen) {
+ /* It all fits in a single encrypt. */
+ return crypto_pk_public_encrypt(env,from,fromlen,to,padding);
+ }
+ cipher = crypto_new_cipher_env(CRYPTO_CIPHER_AES_CTR);
+ if (!cipher) return -1;
+ if (crypto_cipher_generate_key(cipher)<0)
+ goto err;
+ if (padding == RSA_NO_PADDING)
+ cipher->key[0] &= 0x7f;
+ if (crypto_cipher_encrypt_init_cipher(cipher)<0)
+ goto err;
+ memcpy(buf, cipher->key, 16);
+ memcpy(buf+16, from, pkeylen-overhead-16);
+
+ /* Length of symmetrically encrypted data. */
+ symlen = fromlen-(pkeylen-overhead-16);
+
+ outlen = crypto_pk_public_encrypt(env,buf,pkeylen-overhead,to,padding);
+ if (outlen!=pkeylen) {
+ goto err;
+ }
+ r = crypto_cipher_encrypt(cipher,
+ from+pkeylen-overhead-16, symlen,
+ to+outlen);
+
+ if (r<0) goto err;
+ memset(buf, 0, 1024);
+ crypto_free_cipher_env(cipher);
+ return outlen + symlen;
+ err:
+ memset(buf, 0, 1024);
+ if (cipher) crypto_free_cipher_env(cipher);
+ return -1;
+}
+
+/* Invert crypto_pk_public_hybrid_encrypt. */
+int crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, unsigned char *from,
+ int fromlen, unsigned char *to,
+ int padding)
+{
+ int overhead, pkeylen, outlen, r;
+ crypto_cipher_env_t *cipher = NULL;
+ char buf[1024];
+
+ overhead = crypto_get_rsa_padding_overhead(padding);
+ pkeylen = crypto_pk_keysize(env);
+
+ if (fromlen <= pkeylen) {
+ return crypto_pk_private_decrypt(env,from,fromlen,to,padding);
+ }
+ outlen = crypto_pk_private_decrypt(env,from,pkeylen,buf,padding);
+ if (outlen<0) {
+ log_fn(LOG_WARN, "Error decrypting public-key data");
+ return -1;
+ }
+ if (outlen < 16) {
+ log_fn(LOG_WARN, "No room for a symmetric key");
+ return -1;
+ }
+ cipher = crypto_create_init_cipher(CRYPTO_CIPHER_AES_CTR, buf, "", 0);
+ if (!cipher) {
+ return -1;
+ }
+ memcpy(to,buf+16,outlen-16);
+ outlen -= 16;
+ r = crypto_cipher_decrypt(cipher, from+pkeylen, fromlen-pkeylen,
+ to+outlen);
+ if (r<0)
+ goto err;
+ memset(buf,0,1024);
+ crypto_free_cipher_env(cipher);
+ return outlen + (fromlen-pkeylen);
+ err:
+ memset(buf, 0, 1024);
+ if (cipher) crypto_free_cipher_env(cipher);
+ return -1;
+}
+
/* Encode the public portion of 'pk' into 'dest'. Return -1 on error,
* or the number of characters used on success.
*/
Index: crypto.h
===================================================================
RCS file: /home/or/cvsroot/src/common/crypto.h,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- crypto.h 30 Mar 2004 19:47:32 -0000 1.30
+++ crypto.h 1 Apr 2004 03:08:35 -0000 1.31
@@ -59,6 +59,13 @@
int crypto_pk_private_decrypt(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to, int padding);
int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to);
int crypto_pk_public_checksig(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to);
+int crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env, unsigned char *from,
+ int fromlen, unsigned char *to,
+ int padding);
+int crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env, unsigned char *from,
+ int fromlen, unsigned char *to,
+ int padding);
+
#define FINGERPRINT_LEN 49
int crypto_pk_asn1_encode(crypto_pk_env_t *pk, char *dest, int dest_len);
crypto_pk_env_t *crypto_pk_asn1_decode(const char *str, int len);