|
@@ -1144,6 +1144,170 @@ crypto_cipher_decrypt(crypto_cipher_env_t *env, char *to,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#define AES_CIPHER_BLOCK_SIZE (16)
|
|
|
+
|
|
|
+#define AES_IV_SIZE (16)
|
|
|
+
|
|
|
+/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the
|
|
|
+ * symmetric key <b>key</b> of 16 bytes length to <b>to</b> of length
|
|
|
+ * <b>tolen</b> which needs to be <b>fromlen</b>, padded to the next 16
|
|
|
+ * bytes, plus exactly 16 bytes for the initialization vector. On success,
|
|
|
+ * return the number of bytes written, on failure, return -1.
|
|
|
+ */
|
|
|
+int
|
|
|
+crypto_cipher_encrypt_cbc(const char *key, char *to, size_t tolen,
|
|
|
+ const char *from, size_t fromlen)
|
|
|
+{
|
|
|
+
|
|
|
+ EVP_CIPHER_CTX ctx_msg, ctx_iv; /* cipher contexts for message and IV */
|
|
|
+ unsigned char iv[AES_IV_SIZE]; /* initialization vector */
|
|
|
+ int outlen, tmplen; /* length of encrypted strings (w/ and wo/ final data) */
|
|
|
+
|
|
|
+ tor_assert(key);
|
|
|
+ tor_assert(to);
|
|
|
+ tor_assert(tolen >= fromlen + AES_IV_SIZE +
|
|
|
+ (AES_CIPHER_BLOCK_SIZE - fromlen % AES_CIPHER_BLOCK_SIZE));
|
|
|
+ tor_assert(from);
|
|
|
+ tor_assert(fromlen > 0);
|
|
|
+
|
|
|
+ /* generate random initialization vector */
|
|
|
+ crypto_rand((char *)iv, AES_IV_SIZE);
|
|
|
+
|
|
|
+ /* initialize cipher context for the initialization vector */
|
|
|
+ EVP_CIPHER_CTX_init(&ctx_iv);
|
|
|
+
|
|
|
+ /* disable padding for encryption of initialization vector */
|
|
|
+ EVP_CIPHER_CTX_set_padding(&ctx_iv, 0);
|
|
|
+
|
|
|
+ /* set up cipher context for the initialization vector for encryption with
|
|
|
+ * cipher type AES-128 in ECB mode, default implementation, given key, and
|
|
|
+ * no initialization vector */
|
|
|
+ EVP_EncryptInit_ex(&ctx_iv, EVP_aes_128_ecb(), NULL, (unsigned char *)key,
|
|
|
+ NULL);
|
|
|
+
|
|
|
+ /* encrypt initialization vector (no padding necessary) and write it to the
|
|
|
+ * first 16 bytes of the result */
|
|
|
+ if (!EVP_EncryptUpdate(&ctx_iv, (unsigned char *)to, &outlen, iv,
|
|
|
+ AES_IV_SIZE)) {
|
|
|
+ crypto_log_errors(LOG_WARN, "encrypting initialization vector");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* clear all information from cipher context for the initialization vector
|
|
|
+ * and free up any allocated memory associate with it */
|
|
|
+ EVP_CIPHER_CTX_cleanup(&ctx_iv);
|
|
|
+
|
|
|
+ /* initialize cipher context for the message */
|
|
|
+ EVP_CIPHER_CTX_init(&ctx_msg);
|
|
|
+
|
|
|
+ /* set up cipher context for encryption with cipher type AES-128 in CBC mode,
|
|
|
+ * default implementation, given key, and initialization vector */
|
|
|
+ EVP_EncryptInit_ex(&ctx_msg, EVP_aes_128_cbc(), NULL, (unsigned char *)key,
|
|
|
+ iv);
|
|
|
+
|
|
|
+ /* encrypt fromlen bytes from buffer from and write the encrypted version to
|
|
|
+ * buffer to */
|
|
|
+ if (!EVP_EncryptUpdate(&ctx_msg,
|
|
|
+ ((unsigned char *)to) + AES_IV_SIZE, &outlen,
|
|
|
+ (const unsigned char *)from, (int)fromlen)) {
|
|
|
+ crypto_log_errors(LOG_WARN, "encrypting");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* encrypt the final data */
|
|
|
+ if (!EVP_EncryptFinal_ex(&ctx_msg,
|
|
|
+ ((unsigned char *)to) + AES_IV_SIZE + outlen,
|
|
|
+ &tmplen)) {
|
|
|
+ crypto_log_errors(LOG_WARN, "encrypting the final data");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ outlen += tmplen;
|
|
|
+
|
|
|
+ /* clear all information from cipher context and free up any allocated memory
|
|
|
+ * associate with it */
|
|
|
+ EVP_CIPHER_CTX_cleanup(&ctx_msg);
|
|
|
+
|
|
|
+ /* return number of written bytes */
|
|
|
+ return outlen + AES_IV_SIZE;
|
|
|
+}
|
|
|
+
|
|
|
+/** Decrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the
|
|
|
+ * symmetric key <b>key</b> of 16 bytes length to <b>to</b> of length
|
|
|
+ * <b>tolen</b> which may be <b>fromlen</b> minus 16 for the initialization
|
|
|
+ * vector (the size of padding cannot be determined in advance). On success,
|
|
|
+ * return the number of bytes written, on failure (NOT including providing
|
|
|
+ * the wrong key, which occasionally returns the correct length!), return -1.
|
|
|
+ */
|
|
|
+int
|
|
|
+crypto_cipher_decrypt_cbc(const char *key, char *to, size_t tolen,
|
|
|
+ const char *from, size_t fromlen)
|
|
|
+{
|
|
|
+ EVP_CIPHER_CTX ctx_msg, ctx_iv; /* cipher contexts for message and IV */
|
|
|
+ unsigned char iv[AES_IV_SIZE]; /* initialization vector */
|
|
|
+ int outlen, tmplen; /* length of decrypted strings (w/ and wo/ final data) */
|
|
|
+
|
|
|
+ tor_assert(key);
|
|
|
+ tor_assert(to);
|
|
|
+ tor_assert(tolen >= fromlen - AES_IV_SIZE);
|
|
|
+ tor_assert(from);
|
|
|
+ tor_assert(fromlen > 0);
|
|
|
+
|
|
|
+ /* initialize cipher context for the initialization vector */
|
|
|
+ EVP_CIPHER_CTX_init(&ctx_iv);
|
|
|
+
|
|
|
+ /* disable padding for decryption of initialization vector */
|
|
|
+ EVP_CIPHER_CTX_set_padding(&ctx_iv, 0);
|
|
|
+
|
|
|
+ /* set up cipher context for the initialization vector for decryption with
|
|
|
+ * cipher type AES-128 in ECB mode, default implementation, given key, and
|
|
|
+ * no initialization vector */
|
|
|
+ EVP_DecryptInit_ex(&ctx_iv, EVP_aes_128_ecb(), NULL, (unsigned char *)key,
|
|
|
+ NULL);
|
|
|
+
|
|
|
+ /* decrypt initialization vector (is not padded) */
|
|
|
+ if (!EVP_DecryptUpdate(&ctx_iv, iv, &outlen, (const unsigned char *)from,
|
|
|
+ AES_IV_SIZE)) {
|
|
|
+ crypto_log_errors(LOG_WARN, "decrypting initialization vector");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* clear all information from cipher context for the initialization vector
|
|
|
+ * and free up any allocated memory associate with it */
|
|
|
+ EVP_CIPHER_CTX_cleanup(&ctx_iv);
|
|
|
+
|
|
|
+ /* initialize cipher context for the message */
|
|
|
+ EVP_CIPHER_CTX_init(&ctx_msg);
|
|
|
+
|
|
|
+ /* set up cipher context for decryption with cipher type AES-128 in CBC mode,
|
|
|
+ * default implementation, given key, and initialization vector */
|
|
|
+ EVP_DecryptInit_ex(&ctx_msg, EVP_aes_128_cbc(), NULL, (unsigned char *)key,
|
|
|
+ iv);
|
|
|
+
|
|
|
+ /* decrypt fromlen-16 bytes from buffer from and write the decrypted version
|
|
|
+ * to buffer to */
|
|
|
+ if (!EVP_DecryptUpdate(&ctx_msg, (unsigned char *)to, &outlen,
|
|
|
+ ((const unsigned char *)from) + AES_IV_SIZE,
|
|
|
+ (int)fromlen - AES_IV_SIZE)) {
|
|
|
+ crypto_log_errors(LOG_INFO, "decrypting");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* decrypt the final data */
|
|
|
+ if (!EVP_DecryptFinal_ex(&ctx_msg, ((unsigned char *)to) + outlen,
|
|
|
+ &tmplen)) {
|
|
|
+ crypto_log_errors(LOG_INFO, "decrypting the final data");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ outlen += tmplen;
|
|
|
+
|
|
|
+ /* clear all information from cipher context and free up any allocated memory
|
|
|
+ * associate with it */
|
|
|
+ EVP_CIPHER_CTX_cleanup(&ctx_msg);
|
|
|
+
|
|
|
+ /* return number of written bytes */
|
|
|
+ return outlen;
|
|
|
+}
|
|
|
+
|
|
|
/* SHA-1 */
|
|
|
|
|
|
/** Compute the SHA1 digest of <b>len</b> bytes in data stored in
|
|
@@ -1803,6 +1967,64 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
|
dest[i] = '\0';
|
|
|
}
|
|
|
|
|
|
+/** Implements base32 decoding as in rfc3548. Limitation: Requires
|
|
|
+ * that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
|
|
|
+ */
|
|
|
+int
|
|
|
+base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|
|
+{
|
|
|
+ unsigned int nbits, i, j, bit;
|
|
|
+ char *tmp;
|
|
|
+ nbits = srclen * 5;
|
|
|
+
|
|
|
+ tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */
|
|
|
+ tor_assert((nbits/8) <= destlen); /* We need enough space. */
|
|
|
+ tor_assert(destlen < SIZE_T_CEILING);
|
|
|
+
|
|
|
+ /* Convert base32 encoded chars to the 5-bit values that they represent. */
|
|
|
+ tmp = tor_malloc_zero(srclen);
|
|
|
+ for (j = 0; j < srclen; ++j) {
|
|
|
+ if (src[j] > 0x60 && src[j] < 0x7B) tmp[j] = src[j] - 0x61;
|
|
|
+ else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18;
|
|
|
+ else {
|
|
|
+ log_warn(LD_BUG, "illegal character in base32 encoded string");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Assemble result byte-wise by applying five possible cases. */
|
|
|
+ for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) {
|
|
|
+ switch (bit % 40) {
|
|
|
+ case 0:
|
|
|
+ dest[i] = (((uint8_t)tmp[(bit/5)]) << 3) +
|
|
|
+ (((uint8_t)tmp[(bit/5)+1]) >> 2);
|
|
|
+ break;
|
|
|
+ case 8:
|
|
|
+ dest[i] = (((uint8_t)tmp[(bit/5)]) << 6) +
|
|
|
+ (((uint8_t)tmp[(bit/5)+1]) << 1) +
|
|
|
+ (((uint8_t)tmp[(bit/5)+2]) >> 4);
|
|
|
+ break;
|
|
|
+ case 16:
|
|
|
+ dest[i] = (((uint8_t)tmp[(bit/5)]) << 4) +
|
|
|
+ (((uint8_t)tmp[(bit/5)+1]) >> 1);
|
|
|
+ break;
|
|
|
+ case 24:
|
|
|
+ dest[i] = (((uint8_t)tmp[(bit/5)]) << 7) +
|
|
|
+ (((uint8_t)tmp[(bit/5)+1]) << 2) +
|
|
|
+ (((uint8_t)tmp[(bit/5)+2]) >> 3);
|
|
|
+ break;
|
|
|
+ case 32:
|
|
|
+ dest[i] = (((uint8_t)tmp[(bit/5)]) << 5) +
|
|
|
+ ((uint8_t)tmp[(bit/5)+1]);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ tor_free(tmp);
|
|
|
+ tmp = NULL;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/** Implement RFC2440-style iterated-salted S2K conversion: convert the
|
|
|
* <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte
|
|
|
* <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier
|