Commit 96cc85a2 authored by gates's avatar gates
Browse files

Convert libaacs completely over to libgcrypt.

parent 9f2e08c9
......@@ -58,9 +58,8 @@ AC_SYS_LARGEFILE
# required functions
AC_CHECK_FUNC([snprintf],, [AC_MSG_ERROR($function_not_found)])
# openssl check
# check for ECDSA_do_sign, since it's needed
AC_CHECK_LIB([crypto], [ECDSA_do_sign],,
# gcrypt check
AC_CHECK_LIB([gcrypt], [gcry_check_version],,
[AC_MSG_ERROR($library_not_found)])
# function testing for supported compiler options
......
......@@ -38,13 +38,14 @@
#include <inttypes.h>
#include <string.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <gcrypt.h>
int _validate_pk(uint8_t *pk, uint8_t *cvalue, uint8_t *uv, uint8_t *vd,
uint8_t *mk)
{
EVP_CIPHER_CTX ctx;
int a, ret = 0, outlen;
gcry_cipher_hd_t gcry_h;
int a, ret = 0;
uint8_t dec_vd[16];
char str[40];
......@@ -54,21 +55,17 @@ int _validate_pk(uint8_t *pk, uint8_t *cvalue, uint8_t *uv, uint8_t *vd,
DEBUG(DBG_AACS, " cvalue: %s\n", print_hex(str, cvalue, 16));
DEBUG(DBG_AACS, " Verification data: %s\n", print_hex(str, vd, 16));
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit(&ctx, EVP_aes_128_ecb(), pk, NULL);
EVP_DecryptUpdate(&ctx, mk, &outlen, cvalue, 16);
EVP_DecryptFinal(&ctx, mk, &outlen);
EVP_CIPHER_CTX_cleanup(&ctx);
gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
gcry_cipher_setkey(gcry_h, pk, 16);
gcry_cipher_decrypt(gcry_h, mk, 16, cvalue, 16);
for (a = 0; a < 4; a++) {
mk[a + 12] ^= uv[a];
}
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit(&ctx, EVP_aes_128_ecb(), mk, NULL);
EVP_DecryptUpdate(&ctx, dec_vd, &outlen, vd, 16);
EVP_DecryptFinal(&ctx, dec_vd, &outlen);
EVP_CIPHER_CTX_cleanup(&ctx);
gcry_cipher_setkey(gcry_h, mk, 16);
gcry_cipher_decrypt (gcry_h, dec_vd, 16, vd, 16);
gcry_cipher_close(gcry_h);
if (!memcmp(dec_vd, "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8)) {
DEBUG(DBG_AACS, "Processing key is valid!\n");
......@@ -133,7 +130,7 @@ int _calc_mk(AACS *aacs, const char *path)
int _calc_vuk(AACS *aacs, const char *path)
{
int a, outlen;
int a;
MMC* mmc = NULL;
DEBUG(DBG_AACS, "Calculate volume unique key...\n");
......@@ -150,12 +147,12 @@ int _calc_vuk(AACS *aacs, const char *path)
if ((mmc = mmc_open(path, priv_key, cert, nonce, key_point))) {
if (mmc_read_vid(mmc, aacs->vid)) {
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit(&ctx, EVP_aes_128_ecb(), aacs->mk, NULL);
EVP_DecryptUpdate(&ctx, aacs->vuk, &outlen, aacs->vid, 16);
EVP_DecryptFinal(&ctx, aacs->vuk, &outlen);
EVP_CIPHER_CTX_cleanup(&ctx);
gcry_cipher_hd_t gcry_h;
gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES,
GCRY_CIPHER_MODE_ECB, 0);
gcry_cipher_setkey(gcry_h, aacs->mk, 16);
gcry_cipher_decrypt(gcry_h, aacs->vuk, 16, aacs->vid, 16);
gcry_cipher_close(gcry_h);
for (a = 0; a < 16; a++) {
aacs->vuk[a] ^= aacs->vid[a];
......@@ -187,7 +184,7 @@ int _calc_uks(AACS *aacs, const char *path)
uint8_t buf[16];
char f_name[100];
uint64_t f_pos;
int i, outlen;
unsigned int i;
DEBUG(DBG_AACS, "Calculate CPS unit keys...\n");
......@@ -223,12 +220,12 @@ int _calc_uks(AACS *aacs, const char *path)
break;
}
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit(&ctx, EVP_aes_128_ecb(), aacs->vuk, NULL);
EVP_DecryptUpdate(&ctx, aacs->uks + 16*i, &outlen, buf, 16);
EVP_DecryptFinal(&ctx, aacs->uks, &outlen);
EVP_CIPHER_CTX_cleanup(&ctx);
gcry_cipher_hd_t gcry_h;
gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES,
GCRY_CIPHER_MODE_ECB, 0);
gcry_cipher_setkey(gcry_h, aacs->vuk, 16);
gcry_cipher_decrypt(gcry_h, aacs->uks + 16*i, 16, buf, 16);
gcry_cipher_close(gcry_h);
char str[40];
DEBUG(DBG_AACS, "Unit key %d: %s\n", i,
......@@ -344,41 +341,48 @@ int _find_vuk(AACS *aacs, const char *path)
return 0;
}
int _decrypt_unit(AACS *aacs, uint8_t *out, const uint8_t *buf, uint32_t len, uint64_t offset,
int _decrypt_unit(AACS *aacs, uint8_t *buf, uint32_t len, uint64_t offset,
uint32_t curr_uk)
{
int a, outlen;
uint8_t key[32], iv[] = { 0x0b, 0xa0, 0xf8, 0xdd, 0xfe, 0xa6, 0x1f, 0xb3,
0xd8, 0xdf, 0x9f, 0x56, 0x6a, 0x05, 0x0f, 0x78 };
EVP_CIPHER_CTX ctx;
gcry_cipher_hd_t gcry_h;
uint8_t *tmp_buf = malloc(len);
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit(&ctx, EVP_aes_128_ecb(), aacs->uks + curr_uk * 16, NULL);
EVP_EncryptUpdate(&ctx, key, &outlen, buf, 16);
EVP_EncryptFinal(&ctx, key + outlen, &outlen);
EVP_CIPHER_CTX_cleanup(&ctx);
memcpy(tmp_buf, buf, len);
int a;
uint8_t key[16], iv[] = "\x0b\xa0\xf8\xdd\xfe\xa6\x1f\xb3"
"\xd8\xdf\x9f\x56\x6a\x05\x0f\x78";
gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
gcry_cipher_setkey(gcry_h, aacs->uks + curr_uk * 16, 16);
gcry_cipher_encrypt(gcry_h, key, 16, tmp_buf, 16);
gcry_cipher_close(gcry_h);
for (a = 0; a < 16; a++) {
key[a] ^= buf[a];
key[a] ^= tmp_buf[a];
}
memcpy(out, buf, 16);
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit(&ctx, EVP_aes_128_cbc(), key, iv);
EVP_DecryptUpdate(&ctx, out + 16, &outlen, buf + 16, len - 16);
EVP_DecryptFinal(&ctx, out + 16 + outlen, &outlen);
EVP_CIPHER_CTX_cleanup(&ctx);
gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_setkey(gcry_h, key, 16);
gcry_cipher_setiv(gcry_h, iv, 16);
gcry_cipher_decrypt(gcry_h, tmp_buf + 16, len - 16, tmp_buf + 16, len - 16);
gcry_cipher_close(gcry_h);
if (_verify_ts(out, len)) {
DEBUG(DBG_AACS, "Decrypted %s unit [%d bytes] from offset %"PRIu64" (%p)\n",
if (_verify_ts(tmp_buf,len)) {
DEBUG(DBG_AACS, "Decrypted %s unit [%d bytes] from offset %ld (%p)\n",
len % 6144 ? "PARTIAL" : "FULL", len, offset, aacs);
memcpy(buf, tmp_buf, len);
X_FREE(tmp_buf);
return 1;
}
if (curr_uk < aacs->num_uks - (uint32_t)1) {
return _decrypt_unit(aacs, out, buf, len, offset, curr_uk++);
X_FREE(tmp_buf);
if (curr_uk < aacs->num_uks - 1) {
return _decrypt_unit(aacs, buf, len, offset, curr_uk++);
}
return 0;
......@@ -388,6 +392,12 @@ AACS *aacs_open(const char *path, const char *configfile_path)
{
DEBUG(DBG_AACS, "libaacs [%zd]\n", sizeof(AACS));
DEBUG(DBG_AACS, "Initializing libgcrypt...\n");
if (!crypto_init())
{
DEBUG(DBG_AACS, "Failed to initialize libgcrypt\n");
return NULL;
}
char *cfgfile = NULL;
if (configfile_path) {
......@@ -474,13 +484,7 @@ int aacs_decrypt_unit(AACS *aacs, uint8_t *buf, uint32_t len, uint64_t offset)
return 0;
}
uint8_t out[6144];
if (_decrypt_unit(aacs, out, buf, len, offset, 0)) {
memcpy(buf, out, len);
return 1;
}
return 0;
return _decrypt_unit(aacs, buf, len, offset, 0);
}
uint8_t *aacs_get_vid(AACS *aacs)
......
......@@ -28,31 +28,58 @@
*/
#include "crypto.h"
#include "util/strutl.h"
#include <string.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/ecdsa.h>
#include <stdio.h>
#include <gcrypt.h>
#include <pthread.h>
#include <errno.h>
/* Set this in CFLAGS to debug gcrypt MPIs and S-expressions */
#ifndef GCRYPT_DEBUG
#define GCRYPT_DEBUG 0
#endif
/* Use pthread in libgcrypt */
GCRY_THREAD_OPTION_PTHREAD_IMPL;
static int crypto_init_check = 0;
void _aesg3(const uint8_t *src_key, uint8_t *dst_key, uint8_t inc)
{
int a;
gcry_cipher_hd_t gcry_h;
uint8_t seed[16] = { 0x7B, 0x10, 0x3C, 0x5D, 0xCB, 0x08, 0xC4, 0xE5,
0x1A, 0x27, 0xB0, 0x17, 0x99, 0x05, 0x3B, 0xD9 };
seed[15] += inc;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_set_key_length(ctx, 16);
EVP_DecryptInit(ctx, EVP_aes_128_ecb(), src_key, NULL);
EVP_DecryptUpdate(ctx, dst_key, (int*)16, seed, 16);
EVP_DecryptFinal(ctx, dst_key, (int*)16);
EVP_CIPHER_CTX_cleanup(ctx);
gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
gcry_cipher_setkey(gcry_h, src_key, 16);
gcry_cipher_decrypt (gcry_h, dst_key, 16, seed, 16);
gcry_cipher_close(gcry_h);
for (a = 0; a < 16; a++) {
dst_key[a] ^= seed[a];
}
}
/* Initializes libgcrypt */
int crypto_init()
{
if (!crypto_init_check)
{
crypto_init_check = 1;
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
if (!gcry_check_version(GCRYPT_VERSION))
{
crypto_init_check = 0;
}
}
return crypto_init_check;
}
void crypto_aesg3(const uint8_t *D, uint8_t *lsubk, uint8_t* rsubk, uint8_t *pk)
{
if (lsubk) {
......@@ -71,107 +98,168 @@ void crypto_aesg3(const uint8_t *D, uint8_t *lsubk, uint8_t* rsubk, uint8_t *pk)
void crypto_aacs_sign(const uint8_t *c, const uint8_t *pubk, uint8_t *sig,
uint8_t *n, const uint8_t *dhp)
{
EC_GROUP *grp;
const EC_GROUP *pkgrp;
EC_POINT *p;
EC_POINT *pk;
EC_KEY *k;
BIGNUM *bdp, *bda, *bdb, *bdx, *bdy, *bdr;
BIGNUM *x, *y;
BIGNUM *bpk;
BN_CTX *ctx;
EVP_MD_CTX mdctx;
ECDSA_SIG *s;
unsigned char md_value[20], block[60];
unsigned int md_len;
const char *dp = "900812823637587646514106462588455890498729007071";
const char *da = "-3";
const char *db = "366394034647231750324370400222002566844354703832";
const char *dx = "264865613959729647018113670854605162895977008838";
const char *dy = "51841075954883162510413392745168936296187808697";
const char *dr = "900812823637587646514106555566573588779770753047";
ctx = BN_CTX_new();
bdp = BN_new();
bda = BN_new();
bdb = BN_new();
bdx = BN_new();
bdy = BN_new();
bdr = BN_new();
BN_dec2bn(&bdp, dp);
BN_dec2bn(&bda, da);
BN_dec2bn(&bdb, db);
BN_dec2bn(&bdx, dx);
BN_dec2bn(&bdy, dy);
BN_dec2bn(&bdr, dr);
grp = EC_GROUP_new_curve_GFp(bdp, bda, bdb, ctx);
p = EC_POINT_new(grp);
EC_POINT_set_affine_coordinates_GF2m(grp, p, bdx, bdy, ctx);
BN_set_word(bdx, 1);
EC_GROUP_set_generator(grp, p, bdr, bdx);
k = EC_KEY_new();
EC_KEY_set_group(k, grp);
pkgrp = EC_KEY_get0_group(k);
pk = EC_POINT_new(grp);
gcry_mpi_t mpi_d, mpi_md;
gcry_sexp_t sexp_key, sexp_data, sexp_sig, sexp_r, sexp_s;
unsigned char Q[41], block[60], md[20], *r = NULL, *s = NULL;
gpg_error_t err;
char errstr[100];
/* Assign MPI values for ECDSA parameters Q and d.
* Values are:
* Q.x = c[12]..c[31]
* Q.y = c[32]..c[51]
* d = privk
*
* Note: The MPI values for Q are in the form "<format>||Q.x||Q.y".
*/
memcpy(&Q[0], "\x04", 1); // format
memcpy(&Q[1], c + 12, 20); // Q.x
memcpy(&Q[21], c + 32, 20); // Q.y
gcry_mpi_scan(&mpi_d, GCRYMPI_FMT_USG, pubk, 20, NULL);
/* Show the values of the MPIs Q.x, Q.y, and d when debugging */
if (GCRYPT_DEBUG)
{
gcry_mpi_t mpi_Q_x, mpi_Q_y;
gcry_mpi_scan(&mpi_Q_x, GCRYMPI_FMT_USG, c + 12, 20, NULL);
gcry_mpi_scan(&mpi_Q_y, GCRYMPI_FMT_USG, c + 32, 20, NULL);
gcry_mpi_dump(mpi_Q_x);
printf("\n");
gcry_mpi_dump(mpi_Q_y);
printf("\n");
gcry_mpi_dump(mpi_d);
printf("\n");
}
x = BN_bin2bn(c + 12, 20, 0);
y = BN_bin2bn(c + 32, 20, 0);
/* Build the s-expression for the ecdsa private key
* Constant values are:
* p = 900812823637587646514106462588455890498729007071
* a = -3
* b = 366394034647231750324370400222002566844354703832
* G.x = 264865613959729647018113670854605162895977008838
* G.y = 51841075954883162510413392745168936296187808697
* n = 900812823637587646514106555566573588779770753047
*
* Note: Here a = -3 mod p
*/
/* Points are currently only supported in standard format, so get a
* hexstring out of Q.
*/
char str_Q[sizeof(Q)*2];
hex_array_to_hexstring(str_Q, Q, sizeof(Q));
char *strfmt = (char*)malloc(
sizeof("(private-key") +
sizeof("(ecdsa") +
sizeof("(p #9DC9D81355ECCEB560BDB09EF9EAE7C479A7D7DF#)") +
sizeof("(a #9DC9D81355ECCEB560BDB09EF9EAE7C479A7D7DC#)") +
sizeof("(b #402DAD3EC1CBCD165248D68E1245E0C4DAACB1D8#)") +
sizeof("(g #04") +
sizeof("2E64FC22578351E6F4CCA7EB81D0A4BDC54CCEC6") +
sizeof("0914A25DD05442889DB455C7F23C9A0707F5CBB9") +
sizeof("#)") +
sizeof("(n #9DC9D81355ECCEB560BDC44F54817B2C7F5AB017#)") +
sizeof("(q #") + sizeof(str_Q) + sizeof("#)") +
sizeof("(d %m)))") + 1);
sprintf(strfmt,
"(private-key"
"(ecdsa"
"(p #9DC9D81355ECCEB560BDB09EF9EAE7C479A7D7DF#)"
"(a #9DC9D81355ECCEB560BDB09EF9EAE7C479A7D7DC#)"
"(b #402DAD3EC1CBCD165248D68E1245E0C4DAACB1D8#)"
"(g #04"
"2E64FC22578351E6F4CCA7EB81D0A4BDC54CCEC6"
"0914A25DD05442889DB455C7F23C9A0707F5CBB9"
"#)"
"(n #9DC9D81355ECCEB560BDC44F54817B2C7F5AB017#)"
"(q #%s#)"
"(d %%m)))",
str_Q
);
/* Now build the S-expression */
err = gcry_sexp_build(&sexp_key, NULL, strfmt, mpi_d);
if (err)
{
memset(errstr, 0, sizeof(errstr));
gpg_strerror_r(err, errstr, sizeof(errstr));
printf("error was: %s\n", errstr);
return;
}
EC_POINT_set_affine_coordinates_GFp(pkgrp, pk, x, y, NULL);
/* Dump information about the key s-expression when debugging */
if (GCRYPT_DEBUG)
gcry_sexp_dump(sexp_key);
EC_KEY_set_public_key(k, pk);
/* Calculate the sha1 hash from the nonce and host key point and covert
* the hash into an MPI.
*/
memcpy(&block, n, 20);
memcpy(&block[20], dhp, 40);
gcry_md_hash_buffer(GCRY_MD_SHA1, md, block, sizeof(block));
gcry_mpi_scan(&mpi_md, GCRYMPI_FMT_USG, md, sizeof(md), NULL);
/* Dump information about the md MPI when debugging */
if (GCRYPT_DEBUG)
gcry_mpi_dump(mpi_md);
/* Build an s-expression for the hash */
gcry_sexp_build(&sexp_data, NULL,
"(data"
" (flags raw)"
" (value %m))",
mpi_md
);
/* Dump information about the data s-expression when debugging */
if (GCRYPT_DEBUG)
gcry_sexp_dump(sexp_data);
/* Sign the hash with the ECDSA key. The resulting s-expression should be
* in the form:
* (sig-val
* (dsa
* (r r-mpi)
* (s s-mpi)))
*/
err = gcry_pk_sign(&sexp_sig, sexp_data, sexp_key);
if (err)
{
memset(errstr, 0, sizeof(errstr));
gpg_strerror_r(err, errstr, sizeof(errstr));
printf("error was: %s\n", errstr);
return;
}
memset(md_value, 0, 64);
/* Dump information about the signature s-expression when debugging */
if (GCRYPT_DEBUG)
gcry_sexp_dump(sexp_sig);
bpk = BN_bin2bn(pubk, 20, 0);
/* Get the resulting s-expressions for 'r' and 's' */
sexp_r = gcry_sexp_find_token(sexp_sig, "r", 0);
sexp_s = gcry_sexp_find_token(sexp_sig, "s", 0);
EC_KEY_set_private_key(k, bpk);
/* Dump information about 'r' and 's' values when debugging */
if (GCRYPT_DEBUG)
{
gcry_sexp_dump(sexp_r);
gcry_sexp_dump(sexp_s);
}
memcpy(&block, n, 20);
memcpy(&block[20], dhp, 40);
/* Convert the data for 'r' and 's' into unsigned char form */
r = (unsigned char*)gcry_sexp_nth_string(sexp_r, 1);
s = (unsigned char*)gcry_sexp_nth_string(sexp_s, 1);
EVP_MD_CTX_init(&mdctx);
EVP_DigestInit(&mdctx, EVP_sha1());
EVP_DigestUpdate(&mdctx, block, sizeof(block));
EVP_DigestFinal(&mdctx, md_value, &md_len);
s = ECDSA_do_sign(md_value, md_len, k);
BN_bn2bin(s->r, sig);
BN_bn2bin(s->s, sig + 20);
ECDSA_SIG_free(s);
EC_KEY_free(k);
BN_clear_free(bpk);
BN_clear_free(x);
BN_clear_free(y);
EC_POINT_free(pk);
EC_POINT_free(p);
BN_CTX_free(ctx);
BN_free(bdp);
BN_free(bda);
BN_free(bdb);
BN_free(bdx);
BN_free(bdy);
BN_free(bdr);
/* Finally concatenate 'r' and 's' to get the ECDSA signature */
memcpy(sig, r, 20);
memcpy(sig + 20, s, 20);
}
void crypto_aacs_title_hash(const uint8_t *ukf, uint64_t len, uint8_t *hash)
{
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
EVP_DigestInit(ctx, EVP_sha1());
EVP_DigestUpdate(ctx, ukf, len);
EVP_DigestFinal(ctx, hash, NULL);
EVP_MD_CTX_cleanup(ctx);
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, ukf, len);
}
......@@ -32,6 +32,7 @@
#include <stdint.h>
int crypto_init();
void crypto_aesg3(const uint8_t *D, uint8_t *lsubk, uint8_t* rsubk,
uint8_t *pk); // returns left, centre, right keys
void crypto_aacs_sign(const uint8_t *c, const uint8_t *pubk, uint8_t *sig,
......
......@@ -31,6 +31,7 @@
#include "logging.h"
#include <string.h>
#include <stdio.h>
/* Function to assigns proper hex value of character to uint8_t pointer */
int hexstring_to_unsigned_char(uint8_t *value, char c)
......@@ -146,3 +147,20 @@ int hexstring_to_hex_array(uint8_t *hex_array, uint32_t size,
return 1;
}
/* Function to convert a hex array into a hex string.
* str must be allocated by caller
* size is the size of the hex_array
*/
int hex_array_to_hexstring(char *str, const uint8_t *hex_array, uint32_t size)
{
unsigned int i;
for (i = 0; i < size; i++)
{
sprintf(str + (i*2), "%02x", hex_array[i]);
}
return 1;
}
......@@ -34,5 +34,6 @@
int hexstring_to_hex_array(uint8_t *hex_array, uint32_t size,
const char *hexstring);
int hex_array_to_hexstring(char *str, const uint8_t *hex_array, uint32_t size);
#endif // STRUTL_H_
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment