aboutsummaryrefslogtreecommitdiff
path: root/src/common/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r--src/common/crypto.c107
1 files changed, 101 insertions, 6 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 235bd88ff..0763a2c8c 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -13,8 +13,12 @@
#include "orconfig.h"
#ifdef MS_WINDOWS
+#ifndef WIN32_WINNT
#define WIN32_WINNT 0x400
+#endif
+#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
+#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>
@@ -948,7 +952,7 @@ crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const char *data,
log_warn(LD_BUG, "couldn't compute digest");
return -1;
}
- buflen = crypto_pk_keysize(env)+1;
+ buflen = crypto_pk_keysize(env);
buf = tor_malloc(buflen);
r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen);
if (r != DIGEST_LEN) {
@@ -1133,8 +1137,8 @@ crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
warnOnFailure);
}
- buf = tor_malloc(pkeylen+1);
- outlen = crypto_pk_private_decrypt(env,buf,pkeylen+1,from,pkeylen,padding,
+ buf = tor_malloc(pkeylen);
+ outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding,
warnOnFailure);
if (outlen<0) {
log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO,
@@ -1202,9 +1206,6 @@ crypto_pk_asn1_decode(const char *str, size_t len)
{
RSA *rsa;
unsigned char *buf;
- /* This ifdef suppresses a type warning. Take out the first case once
- * everybody is using OpenSSL 0.9.7 or later.
- */
const unsigned char *cp;
cp = buf = tor_malloc(len);
memcpy(buf,str,len);
@@ -1245,6 +1246,32 @@ crypto_pk_get_digest(crypto_pk_env_t *pk, char *digest_out)
return 0;
}
+/** Compute all digests of the DER encoding of <b>pk</b>, and store them
+ * in <b>digests_out</b>. Return 0 on success, -1 on failure. */
+int
+crypto_pk_get_all_digests(crypto_pk_env_t *pk, digests_t *digests_out)
+{
+ unsigned char *buf, *bufp;
+ int len;
+
+ len = i2d_RSAPublicKey(pk->key, NULL);
+ if (len < 0)
+ return -1;
+ buf = bufp = tor_malloc(len+1);
+ len = i2d_RSAPublicKey(pk->key, &bufp);
+ if (len < 0) {
+ crypto_log_errors(LOG_WARN,"encoding public key");
+ tor_free(buf);
+ return -1;
+ }
+ if (crypto_digest_all(digests_out, (char*)buf, len) < 0) {
+ tor_free(buf);
+ return -1;
+ }
+ tor_free(buf);
+ return 0;
+}
+
/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces
* every four spaces. */
/* static */ void
@@ -1714,6 +1741,74 @@ crypto_hmac_sha1(char *hmac_out,
(unsigned char*)hmac_out, NULL);
}
+/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
+ * the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result
+ * in <b>hmac_out</b>.
+ */
+void
+crypto_hmac_sha256(char *hmac_out,
+ const char *key, size_t key_len,
+ const char *msg, size_t msg_len)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000l)
+ /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
+ tor_assert(key_len < INT_MAX);
+ tor_assert(msg_len < INT_MAX);
+ HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
+ (unsigned char*)hmac_out, NULL);
+#else
+ /* OpenSSL doesn't have an EVP implementation for SHA256. We'll need
+ to do HMAC on our own.
+
+ HMAC isn't so hard: To compute HMAC(key, msg):
+ 1. If len(key) > blocksize, key = H(key).
+ 2. If len(key) < blocksize, right-pad key up to blocksize with 0 bytes.
+ 3. let ipad = key xor 0x363636363636....36
+ let opad = key xor 0x5c5c5c5c5c5c....5c
+ The result is H(opad | H( ipad | msg ) )
+ */
+#define BLOCKSIZE 64
+#define DIGESTSIZE 32
+ uint8_t k[BLOCKSIZE];
+ uint8_t pad[BLOCKSIZE];
+ uint8_t d[DIGESTSIZE];
+ int i;
+ SHA256_CTX st;
+
+ tor_assert(key_len < INT_MAX);
+ tor_assert(msg_len < INT_MAX);
+
+ if (key_len <= BLOCKSIZE) {
+ memset(k, 0, sizeof(k));
+ memcpy(k, key, key_len); /* not time invariant in key_len */
+ } else {
+ SHA256((const uint8_t *)key, key_len, k);
+ memset(k+DIGESTSIZE, 0, sizeof(k)-DIGESTSIZE);
+ }
+ for (i = 0; i < BLOCKSIZE; ++i)
+ pad[i] = k[i] ^ 0x36;
+ SHA256_Init(&st);
+ SHA256_Update(&st, pad, BLOCKSIZE);
+ SHA256_Update(&st, (uint8_t*)msg, msg_len);
+ SHA256_Final(d, &st);
+
+ for (i = 0; i < BLOCKSIZE; ++i)
+ pad[i] = k[i] ^ 0x5c;
+ SHA256_Init(&st);
+ SHA256_Update(&st, pad, BLOCKSIZE);
+ SHA256_Update(&st, d, DIGESTSIZE);
+ SHA256_Final((uint8_t*)hmac_out, &st);
+
+ /* Now clear everything. */
+ memset(k, 0, sizeof(k));
+ memset(pad, 0, sizeof(pad));
+ memset(d, 0, sizeof(d));
+ memset(&st, 0, sizeof(st));
+#undef BLOCKSIZE
+#undef DIGESTSIZE
+#endif
+}
+
/* DH */
/** Shared P parameter for our circuit-crypto DH key exchanges. */