libaacs | branch: master | npzacs <npz...@gmail.com> | Thu Jul 4 13:06:50 2013 +0300| [ece6afdb73546be4aadf05ccc30dc4e745f27999] | committer: npzacs
Calculate bus key and use it to verify message authentication codes > http://git.videolan.org/gitweb.cgi/libaacs.git/?a=commit;h=ece6afdb73546be4aadf05ccc30dc4e745f27999 --- src/libaacs/crypto.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++- src/libaacs/crypto.h | 3 ++ src/libaacs/mmc.c | 36 +++++++++++++--- 3 files changed, 147 insertions(+), 8 deletions(-) diff --git a/src/libaacs/crypto.c b/src/libaacs/crypto.c index fc94f1f..2898779 100644 --- a/src/libaacs/crypto.c +++ b/src/libaacs/crypto.c @@ -1,7 +1,7 @@ /* * This file is part of libaacs * Copyright (C) 2009-2010 Obliter0n - * Copyright (C) 2010 npzacs + * Copyright (C) 2010-2013 npzacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -151,6 +151,67 @@ void crypto_aesg3(const uint8_t *D, uint8_t *lsubk, uint8_t* rsubk, uint8_t *pk) } } +/* + * AES CMAC + */ + +static void _shl_128(unsigned char *dst, const unsigned char *src) +{ + uint8_t overflow = 0; + int i; + + for (i = 15; i >= 0; i--) { + dst[i] = (src[i] << 1) | overflow; + overflow = src[i] >> 7; + } +} + +static void _cmac_key(const unsigned char *aes_key, unsigned char *k1, unsigned char *k2) +{ + uint8_t key[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + gcry_cipher_hd_t gcry_h; + + gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0); + gcry_cipher_setkey(gcry_h, aes_key, 16); + gcry_cipher_encrypt (gcry_h, key, 16, NULL, 0); + gcry_cipher_close(gcry_h); + + _shl_128(k1, key); + if (key[0] & 0x80) { + k1[15] ^= 0x87; + } + + _shl_128(k2, k1); + if (k1[0] & 0x80) { + k2[15] ^= 0x87; + } +} + +void crypto_aes_cmac_16(const unsigned char *data, const unsigned char *aes_key, unsigned char *cmac) +{ + gcry_cipher_hd_t gcry_h; + uint8_t k1[16], k2[16]; + unsigned ii; + + /* + * Somplified version of AES CMAC. Spports only 16-byte input data. + */ + + /* generate CMAC keys */ + _cmac_key(aes_key, k1, k2); + + memcpy(cmac, data, 16); + for (ii = 0; ii < 16; ii++) { + cmac[ii] ^= k1[ii]; + } + + gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0); + gcry_cipher_setkey(gcry_h, aes_key, 16); + gcry_cipher_encrypt (gcry_h, cmac, 16, 0, 16); + gcry_cipher_close(gcry_h); +} + + #if defined(HAVE_STRERROR_R) && defined(HAVE_LIBGPG_ERROR) #define LOG_GCRY_ERROR(msg, func, err) \ char errstr[100] = {0}; \ @@ -503,6 +564,59 @@ void crypto_create_nonce(uint8_t *buf, size_t len) gcry_create_nonce(buf, len); } +void crypto_create_bus_key(const uint8_t *priv_key, const uint8_t *drive_key_point, unsigned char *bus_key) +{ + /* init AACS curve */ + + elliptic_curve_t ec; + _aacs_curve_init(&ec); + + /* init ec context */ + + mpi_ec_t ctx = _gcry_mpi_ec_init (ec.p, ec.a); + + /* parse input data */ + + gcry_mpi_t mpi_priv_key = NULL; + gcry_mpi_scan (&mpi_priv_key, GCRYMPI_FMT_USG, priv_key, 20, NULL); + + mpi_point_t Q; + point_init (&Q); + gcry_mpi_scan (&Q.x, GCRYMPI_FMT_USG, drive_key_point, 20, NULL); + gcry_mpi_scan (&Q.y, GCRYMPI_FMT_USG, drive_key_point + 20, 20, NULL); + Q.z = mpi_alloc_set_ui(1); + + /* calculate bus key point: multiply drive key point with private key */ + + mpi_point_t bus_key_point; + point_init (&bus_key_point); + _gcry_mpi_ec_mul_point (&bus_key_point, mpi_priv_key, &Q, ctx); + + /* bus key is lowest 128 bits of bus_key_point x-coordinate */ + + /* get affine coordinates (Hv) */ + gcry_mpi_t q_x = mpi_new(0); + gcry_mpi_t q_y = mpi_new(0); + _gcry_mpi_ec_get_affine (q_x, q_y, &bus_key_point, ctx); + + /* convert to binary */ + uint8_t q_x_bin[100]; + size_t n = 0; + gcry_mpi_print (GCRYMPI_FMT_USG, q_x_bin, sizeof(q_x_bin), &n, q_x); + + memcpy(bus_key, q_x_bin + n - 16, 16); + + /* cleanup */ + + _gcry_mpi_ec_free (ctx); + _curve_free(&ec); + mpi_free(mpi_priv_key); + point_free(&Q); + point_free(&bus_key_point); + mpi_free(q_x); + mpi_free(q_y); +} + void crypto_create_host_key_pair(uint8_t *host_key, uint8_t *host_key_point) { /* diff --git a/src/libaacs/crypto.h b/src/libaacs/crypto.h index d823f22..b3e20aa 100644 --- a/src/libaacs/crypto.h +++ b/src/libaacs/crypto.h @@ -28,6 +28,8 @@ AACS_PRIVATE int crypto_init(void); AACS_PRIVATE void crypto_aesg3(const uint8_t *D, uint8_t *lsubk, uint8_t* rsubk, uint8_t *pk); // returns left, centre, right keys +AACS_PRIVATE void crypto_aes_cmac_16(const unsigned char *data, const unsigned char *aes_key, unsigned char *cmac); + AACS_PRIVATE void crypto_aacs_sign(const uint8_t *cert, const uint8_t *priv_key, uint8_t *signature, const uint8_t *nonce, const uint8_t *point); @@ -41,5 +43,6 @@ AACS_PRIVATE int crypto_aacs_verify_drive_cert(const uint8_t *cert); AACS_PRIVATE void crypto_create_host_key_pair(uint8_t *key, uint8_t *key_point); AACS_PRIVATE void crypto_create_nonce(uint8_t *buf, size_t len); +AACS_PRIVATE void crypto_create_bus_key(const uint8_t *priv_key, const uint8_t *drive_key_point, unsigned char *bus_key); #endif /* CRYPTO_H_ */ diff --git a/src/libaacs/mmc.c b/src/libaacs/mmc.c index 08a6901..105ca00 100644 --- a/src/libaacs/mmc.c +++ b/src/libaacs/mmc.c @@ -1014,7 +1014,7 @@ static int _verify_signature(const uint8_t *cert, const uint8_t *signature, int mmc_read_vid(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cert, uint8_t *vid, uint8_t *pmsn) { - uint8_t agid = 0, hks[40], dn[20], dc[92], dkp[40], dks[40], mac[16]; + uint8_t agid = 0, hks[40], dn[20], dc[92], dkp[40], dks[40], mac[16], calc_mac[16], bus_key[16]; char str[512]; int error_code = MMC_ERROR; @@ -1096,18 +1096,40 @@ int mmc_read_vid(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cer break; } + // calculate bus key + crypto_create_bus_key(mmc->host_key, dkp, bus_key); + if (DEBUG_KEYS) { + DEBUG(DBG_MMC, "Bus Key : %s\n", print_hex(str, bus_key, 16)); + } + + } while (0); if (_mmc_read_vid(mmc, agid, vid, mac)) { - DEBUG(DBG_MMC, "VID: %s\n", print_hex(str, vid, 16)); - DEBUG(DBG_MMC, "MAC: %s\n", print_hex(str, mac, 16)); - /* TODO: verify MAC */ + if (DEBUG_KEYS) { + DEBUG(DBG_MMC, "VID : %s\n", print_hex(str, vid, 16)); + DEBUG(DBG_MMC, "VID MAC : %s\n", print_hex(str, mac, 16)); + } + + /* verify MAC */ + crypto_aes_cmac_16(vid, bus_key, calc_mac); + if (memcmp(calc_mac, mac, 16)) { + DEBUG(DBG_MMC | DBG_CRIT, "VID MAC is incorrect. This means this Volume ID is not correct.\n"); + } /* read pmsn */ if (_mmc_read_pmsn(mmc, agid, pmsn, mac)) { - DEBUG(DBG_MMC, "PMSN: %s\n", print_hex(str, pmsn, 16)); - DEBUG(DBG_MMC, "MAC: %s\n", print_hex(str, mac, 16)); - /* TODO: verify MAC */ + if (DEBUG_KEYS) { + DEBUG(DBG_MMC, "PMSN : %s\n", print_hex(str, pmsn, 16)); + DEBUG(DBG_MMC, "PMSN MAC : %s\n", print_hex(str, mac, 16)); + } + + /* verify CMAC */ + crypto_aes_cmac_16(vid, bus_key, calc_mac); + if (memcmp(calc_mac, mac, 16)) { + DEBUG(DBG_MMC | DBG_CRIT, "PMSN MAC is incorrect. This means PMSN is not correct.\n"); + } + } else { memset(pmsn, 0, 16); DEBUG(DBG_MMC | DBG_CRIT, "Unable to read PMSN from drive!\n"); _______________________________________________ libaacs-devel mailing list libaacs-devel@videolan.org http://mailman.videolan.org/listinfo/libaacs-devel