#include #include #include #include #include #include #include #include "dl_pkts.h" #include "libusb.h" #include "pkts.h" #include "hdcp.h" #include #include #include #include #include #include #include #include #define KD_SIZE 32 struct hdcp_session_info { gcry_sexp_t pub_key; uint8_t calc_h[32]; uint8_t calc_l[32]; uint8_t rrx[8]; bool h_matches; bool l_matches; bool is_repeater; bool got_h_prime; EVP_CIPHER_CTX aes_ctx; /* ctx for cipher */ uint8_t kd[KD_SIZE]; uint8_t edkey_ks[16]; const uint8_t *rtx; const uint8_t *km; const uint8_t *ks; }; static int VID = 0x17e9; static int PID = 0x4300; /* make km all 0s for now */ static unsigned char mykm[16] = { 0xcd, 0xef, 0x65, 0x33, 0x69, 0x23, 0xfa, 0x3e, 0x60, 0xee, 0xdd, 0x5c, 0xce, 0xfb, 0x39, 0x19 }; static unsigned char myfakekm[16] = { 0x16, 0xC6, 0xE5, 0xF6, 0x1B, 0x65, 0x5C, 0xBC, 0x79, 0xC9, 0xC2, 0xCC, 0x03, 0x91, 0xC2, 0x36 }; static unsigned char forgekm[16] = { 0x72, 0x9d, 0x7d, 0xd6, 0x6c, 0x2e, 0xa6, 0x55, 0xf3, 0xb4, 0x1f, 0x93, 0x1a, 0x5a, 0xd9, 0xeb }; static const uint8_t Rtx[] = { 0x84, 0xd7, 0xcf, 0x64, 0x2d, 0x68, 0xff, 0xd5 }; static const uint8_t lc_Rn[] = { 0xd7, 0xfa, 0xf6, 0x99, 0x14, 0xd2, 0x51, 0xe0 }; static const uint8_t riv[] = { 0xea, 0xc1, 0x6d, 0xd3, 0x07, 0xf0, 0x5c, 0x9b}; /* session key */ static unsigned char myks[16] = { 0xcf, 0xef, 0x65, 0x33, 0x69, 0x23, 0xfa, 0x3e, 0x61, 0xee, 0xdd, 0x5c, 0xce, 0xfb, 0x39, 0x19}; static unsigned char myks2[16] = { 0x55, 0xf9, 0x55, 0x87, 0xaf, 0x69, 0x22, 0x9a, 0x4f, 0x2a, 0xb2, 0x70, 0xce, 0x3f, 0xec, 0xf4 }; /* sent from host to USB */ static const uint8_t edkey_ks[16] = { 0x60, 0x06, 0x77, 0xE4, 0x5F, 0xD1, 0xCF, 0x5A, 0x62, 0x2D, 0xFE, 0x25, 0xBC, 0xD2, 0x9F, 0x92 }; static const uint8_t fake_rrx[8] = { 0xCC, 0x28, 0xA9, 0x8B, 0x61, 0x32, 0x44, 0x07 }; static const uint8_t mypkt_enc_data[] = {0xCF, 0xD2, 0x64, 0x70, 0x10, 0x8E, 0x5F, 0xAC, 0xD8, 0xB2, 0xD6, 0xC2, 0x2C, 0x2F, 0xCA, 0xBE, 0x94, 0x92, 0x37, 0xA9, 0x8B, 0x21, 0xF3, 0xC6, 0x28, 0x29, 0xB1, 0x0C, 0xA8, 0x93, 0x8F, 0xDD, 0x3B, 0x53, 0xE3, 0xDA, 0xE3, 0xFA, 0xC3, 0x1C, 0xCF, 0xEC, 0xBE, 0x7C, 0x90, 0x49, 0xAD, 0x86}; static const uint8_t mypkt_out_data2[] = {0x51, 0x24, 0xA9, 0x18, 0x9C, 0xAA, 0x2F, 0x09, 0xE1, 0x49, 0xB4, 0xED, 0x2C, 0x16, 0xB1, 0xB1, 0xF0, 0x87, 0xF7, 0x46, 0xAD, 0xCC, 0x4F, 0xE6, 0xAB, 0x71, 0xE1, 0x30, 0x07, 0x01, 0xA4, 0x3F, 0xC7, 0xE1, 0x05, 0x1F, 0x0A, 0x4E, 0xD5, 0xCB, 0x4A, 0xAF, 0x14, 0x30, 0x88, 0xD9, 0x5A, 0x57}; static const uint8_t mypkt_repl_data[] = {0x1E, 0x6C, 0x0C, 0xD7, 0x48, 0xF7, 0x67, 0xB8, 0x92, 0x0D, 0x42, 0x5D, 0x44, 0xB3, 0xF9, 0x71, 0x7F, 0xF3, 0x94, 0x3E, 0x76, 0xE2, 0xE0, 0xEA, 0xCB, 0x2B, 0xE4, 0x0E, 0x57, 0x14, 0x91, 0xEF, 0x86, 0xC6, 0x69, 0x22, 0x53, 0x92, 0x10, 0xEC, 0xC2, 0xEE, 0x10, 0x2A, 0x21, 0x0F, 0x2E, 0xD9, 0xAF, 0xA7, 0x70, 0x90, 0x47, 0xB9, 0x61, 0x17, 0xDF, 0xFE, 0x93, 0x3F, 0x70, 0x8F, 0x90, 0x3D, 0xB4, 0xF3, 0x98, 0x1A, 0xC9, 0x4B, 0xBE, 0xCD, 0xB2, 0xD1, 0x82, 0x19, 0xCF, 0x9C, 0x4F, 0x72, 0xDB, 0xF7, 0xA8, 0x5E, 0x91, 0x85, 0xAC, 0x15, 0xCE, 0x35, 0x65, 0x6D, 0x77, 0x3D, 0xFB, 0xA7}; static const uint8_t mypkt_repl2_data[] = {0x87, 0x6D, 0x20, 0xBA, 0x27, 0x24, 0xE6, 0x8A, 0x42, 0x79, 0x10, 0x0E, 0xDC, 0x99, 0x7F, 0x16, 0xD0, 0xC0, 0xCC, 0x8C, 0xBE, 0x67, 0x2C, 0x04, 0x07, 0xB4, 0xFD, 0x51, 0xF2, 0xB9, 0x16, 0xFB, 0xC0, 0xD9, 0xE7, 0x66, 0x2B, 0x1F, 0x09, 0x23, 0x44, 0xF8, 0xF3, 0x0E, 0x84, 0x81, 0xFE, 0x53, 0x1C, 0x8D, 0x7C, 0x84, 0x53, 0x3F, 0x0A, 0xFD, 0x8D, 0xA4, 0x5F, 0x49, 0xAC, 0x69, 0x3B, 0x1C, 0xF9, 0x6E, 0x86, 0xC1, 0x17, 0x7A, 0xF9, 0xF9, 0x90, 0x9D, 0xF3, 0xFB, 0xA4, 0x65, 0x7D, 0xA5, 0x79, 0xF9, 0x68, 0x9F, 0x44, 0x43, 0x5E, 0x52, 0xCA, 0x69, 0xCC, 0x47, 0x66, 0xCF, 0xF8, 0x47, 0x07, 0xFC, 0xDE, 0x90, 0xCA, 0x55, 0x5E, 0xA4, 0x8A, 0x03, 0x92, 0xC7, 0xFA, 0x67, 0x71, 0xA1, 0xE4, 0x25, 0x97, 0xAB, 0x25, 0x78, 0x78, 0x08, 0x19, 0xFC, 0xFA, 0x63, 0x41, 0xAD, 0x67, 0x6E, 0x89, 0x28, 0x7D, 0xF6, 0xA6, 0x57, 0x8C, 0x57, 0x9C, 0xFB, 0x19, 0xDD, 0x26, 0x0A, 0xFD, 0x06, 0x35, 0xA6, 0xE0, 0x01, 0xA1, 0x0E, 0x46, 0xE6, 0x80, 0x29, 0xFD, 0x41, 0xFB, 0xA1, 0x33, 0xDC, 0x39, 0xC1, 0xBE, 0xD7, 0x27, 0xF2, 0xC5, 0x1D, 0x37, 0x52, 0x4C, 0x20, 0x30, 0x4C, 0x9E, 0x3B, 0xF1, 0x5F, 0x54, 0x4D, 0x32, 0xE3, 0xB1, 0xAC, 0xE1, 0xC1, 0x10, 0xEA, 0x92, 0xFB, 0xBF, 0x6A, 0xE1, 0xFE, 0xCE, 0x7A, 0xC0, 0xF5, 0x3C, 0xD3, 0x11, 0xC4, 0x4E, 0xCE, 0x5D, 0x4E, 0xA2, 0x57, 0x72, 0x4B, 0x72, 0x4A, 0x60, 0x05, 0x89, 0xB0, 0x9D, 0x17, 0x3D, 0x8C, 0xAB, 0x63, 0x26, 0x5A, 0x97, 0x6F, 0x65, 0x5A, 0xAE, 0xDE, 0xE5, 0x9F, 0xC2, 0x9E, 0x9B, 0x7B, 0xA9, 0x60, 0xD7, 0x7F, 0x76, 0x34, 0xFA, 0x92, 0xCC, 0x83, 0x81, 0x16, 0xE3, 0x42, 0x70, 0xD7, 0x09, 0x57, 0x50, 0x63, 0xDA, 0x21, 0x59, 0xE6, 0xCA, 0xE2, 0x2C, 0x9F, 0x2E, 0xEA, 0x75, 0xAC, 0x67, 0xD7, 0x73, 0x7F, 0x2C, 0x7E, 0x6A, 0x3C, 0x84, 0xEE, 0x63, 0x8A, 0x12, 0x4D, 0xAD, 0x98, 0x29, 0xFA, 0x52, 0xB1, 0xC9, 0x6C, 0xBA, 0x69, 0xDC, 0x3C, 0x44, 0x46, 0xF7, 0xF9, 0xD9, 0x30, 0xE4, 0x92, 0x5A, 0x55, 0xED, 0x1D, 0xDB, 0x66, 0x26, 0x41, 0xE7, 0xD5, 0x4F, 0x7F, 0x3C, 0x65, 0xE9, 0x99, 0x57, 0xA5, 0xC8, 0xD7, 0x8C, 0xCF, 0x20, 0xB9, 0x4E, 0xEB, 0xB2, 0x7A, 0xAB, 0x63, 0xDB, 0x4E, 0xDB, 0x63, 0x1C, 0xCE, 0x4D, 0x81, 0x67, 0xCE, 0xA5, 0x6D, 0xAD, 0xB7, 0xA5, 0xCA, 0x46, 0xE0, 0x30, 0xBF, 0xF0, 0x03, 0xC9, 0xBE, 0xB6, 0x22, 0xE5, 0x15, 0x8D, 0xDF, 0x38, 0xBF, 0xF7, 0xE9, 0xEE, 0xBA, 0x47, 0x9D, 0xEB, 0x6E, 0x4B, 0x28, 0xF8, 0xDD, 0xAD, 0x61, 0xF7, 0x78, 0x4E, 0x7B, 0x6C, 0xAE, 0x89, 0xDD, 0x6A, 0xEC, 0xDC, 0x3C, 0x03, 0xEB, 0x05, 0x2F, 0xDF, 0xA6, 0x68, 0x1E, 0xD6, 0x8E, 0x87, 0x8A, 0x97, 0xC8, 0x7A, 0x43, 0xB0, 0x95, 0xE5, 0xEE, 0x63, 0x65, 0xFF, 0x8A, 0x6C, 0x1F, 0x89, 0x45, 0xDF, 0xE4, 0x8F, 0xC9, 0x29, 0xE3, 0xBA, 0xB2, 0x10, 0x91, 0x2D, 0x02, 0xB0, 0x20, 0xAA, 0x44, 0x31, 0xBE, 0x08, 0x78, 0x3A, 0xCC, 0xD1, 0xA3, 0x90, 0xCA, 0xD2, 0x4F, 0x0A, 0x45, 0x99, 0x1F, 0x5A, 0x32, 0x4A, 0xEC, 0x81, 0xAD, 0x79, 0x37, 0x25, 0x37, 0xBF, 0xD2, 0xEA, 0x29, 0x33, 0xF8, 0xF8, 0x44, 0xFC, 0x19, 0x26, 0x5C, 0xF9, 0x7E, 0x5D, 0xB2, 0x73, 0x44, 0x49, 0x68, 0x1B, 0x3A, 0xF4, 0x37, 0x59, 0x3C, 0x20, 0x1D, 0x6B, 0xEB, 0x5A, 0x8D, 0xB4, 0x72, 0xC4, 0x35, 0x8A, 0x42, 0xBE, 0xFA, 0x80, 0x44, 0x16, 0x60, 0x8C, 0x0F, 0x3F, 0x56, 0xD7, 0x6F, 0xC4, 0x79, 0xA0, 0xEC, 0xA2, 0xA1, 0x62, 0xE1, 0x1E, 0xE7, 0x57, 0x96, 0x6E, 0xDB, 0x0A, 0x8D, 0xE3, 0xA2, 0x28, 0xC5, 0x71, 0xF9, 0x3E, 0x71, 0xC6, 0xCF, 0x6F, 0x36, 0xAC, 0x92, 0xF3, 0xBC, 0xF7, 0xE6, 0xDE, 0x4D, 0x34, 0x4E, 0x64, 0x57, 0x1D, 0xFF, 0x19, 0xC6, 0x81, 0x1B, 0x34, 0x7C, 0x6B, 0x10}; static const uint8_t fakelc128[16] = {}; //{0x93, 0xce, 0x5a, 0x56, 0xa0, 0xa1, 0xf4, 0xf7, 0x3c, 0x65, 0x8a, 0x1b, 0xd2, 0xae, 0xf0, 0xf7}; static const uint8_t possiblelc128[16] = {}; static int create_gcrypt_pubkey(struct hdcp_session_info *info, const uint8_t *n, const uint8_t *e, int n_len, int e_len) { char buf[65536]; char temp[10]; int ret; int i; buf[0] = 0; strcat(buf, "(public-key\n"); strcat(buf, " (rsa\n"); strcat(buf, " (n #"); for (i = 0; i < n_len; i++) { sprintf(temp,"%02x", n[i]); strcat(buf, temp); } strcat(buf, "#)\n"); strcat(buf, " (e #"); for (i = 0; i < e_len; i++) { sprintf(temp,"%02x", e[i]); strcat(buf, temp); } strcat(buf, "#)\n"); strcat(buf, " )\n"); strcat(buf, ")\n"); printf("pub key %s\n", buf); ret = gcry_sexp_sscan(&info->pub_key, NULL, buf, strlen(buf)); if (ret != 0) return -1; return 0; } static int create_gcrypt_km(gcry_sexp_t *km, const uint8_t *km_str, int km_len) { char buf[65536]; char temp[10]; int i, ret; buf[0] = 0; strcat(buf, "(data\n"); strcat(buf, " (flags oaep)\n"); strcat(buf, " (hash-algo sha256)\n"); strcat(buf, " (labal \"km\")\n"); strcat(buf, " (value #"); for (i = 0; i < km_len; i++) { sprintf(temp,"%02x", km_str[i]); strcat(buf, temp); } strcat(buf, "#))\n"); printf("km buf %s\n", buf); ret = gcry_sexp_sscan(km, NULL, buf, strlen(buf)); if (ret != 0) return -1; return 0; } #define KD_SIZE 32 #define NULL_BYTES \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 static void calc_ks_ctr(struct hdcp_session_info *info, uint32_t streamctr, uint64_t input_ctr, uint8_t *buf, const uint8_t *in_buf) { uint8_t tmp[100]; uint8_t iv[16]; uint8_t kslc128[16]; int outl; int ret; int i; memset(iv, 0, 16); memcpy(iv, riv, 8); /* iv = (Riv XORG streamCtr) || inputCtr */ /* streamctr */ iv[6] ^= (streamctr >> 8) & 0xff; iv[7] ^= streamctr & 0xff; iv[sizeof(iv)-1] = input_ctr; memcpy(kslc128, info->ks, 16); /* input claimed to be Ks XOR lc128 */ for (i = 0; i < 16; i++) { /* removing the XOR gives the hd0;]u; pattern in first packet which could be a false positive */ kslc128[i] ^= possiblelc128[i]; } ret = EVP_EncryptInit_ex(&info->aes_ctx, EVP_aes_128_ctr(), NULL, kslc128, iv); assert(ret == 1); ret = EVP_EncryptUpdate(&info->aes_ctx, buf, &outl, in_buf, 16); assert(ret == 1); assert(outl == 16); ret = EVP_EncryptFinal_ex(&info->aes_ctx, tmp, &outl); assert(ret == 1); assert(outl == 0); } static void calc_kd_ctr(struct hdcp_session_info *info, uint8_t ctr, uint8_t *buf) { uint8_t tmp[100]; unsigned char input[] = {NULL_BYTES, NULL_BYTES}; uint8_t iv[16]; int outl; int ret; memset(iv, 0, 16); memcpy(iv, info->rtx, 8); iv[sizeof(iv)-1] = ctr; /* iv is now r_tx|ctr */ ret = EVP_EncryptInit_ex(&info->aes_ctx, EVP_aes_128_ctr(), NULL, info->km, iv); assert(ret == 1); ret = EVP_EncryptUpdate(&info->aes_ctx, buf, &outl, input, sizeof(input)); assert(ret == 1); assert(outl == sizeof(input)); ret = EVP_EncryptFinal_ex(&info->aes_ctx, tmp, &outl); assert(ret == 1); assert(outl == 0); } static void calculate_kd(struct hdcp_session_info *info) { uint8_t *buf; buf = info->kd; memset(buf, 0, KD_SIZE); calc_kd_ctr(info, 0, buf); calc_kd_ctr(info, 1, &buf[16]); } static void calculate_hacker_key(struct hdcp_session_info *info) { uint8_t *buf = info->edkey_ks; int i; calc_kd_ctr(info, 2, buf); /* we have dkey2 in buf now */ printf("dkey2:"); for (i = 0; i < 16; i++) { printf("%02x", buf[i]); } for (i = 0; i < 8; i++) { buf[8 + i] ^= fake_rrx[i]; } for (i = 0; i < 16; i++) { buf[i] ^= edkey_ks[i]; } printf("posks:"); for (i = 0; i < 16; i++) { printf("%02x", buf[i]); } } static void calculate_edkey_ks(struct hdcp_session_info *info) { uint8_t *buf = info->edkey_ks; int i; calc_kd_ctr(info, 2, buf); /* we have dkey2 in buf now */ printf("dkey2:"); for (i = 0; i < 16; i++) { printf("%02x", buf[i]); } printf("\n"); for (i = 0; i < 8; i++) { buf[8 + i] ^= info->rrx[i]; } for (i = 0; i < 16; i++) { buf[i] ^= info->ks[i]; } } static int calculate_h(struct hdcp_session_info *info) { HMAC_CTX ctx; unsigned char res[200]; unsigned int resLen; uint8_t input[8]; memcpy(input, info->rtx, 8); if (info->is_repeater) input[7] ^= 0x1; HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, info->kd, KD_SIZE, EVP_sha256(), NULL); HMAC_Update(&ctx, input, 8); HMAC_Final(&ctx, res, &resLen); HMAC_CTX_cleanup(&ctx); if (resLen != 32) return -1; memcpy(info->calc_h, res, resLen); return 0; } static int calculate_l(struct hdcp_session_info *info) { HMAC_CTX ctx; unsigned char res[200]; unsigned int resLen; int i; uint8_t input[8]; uint8_t kdbuf[KD_SIZE]; memcpy(kdbuf, info->kd, KD_SIZE); for (i = 0; i < 8; i++) { kdbuf[24 + i] ^= info->rrx[i]; } memcpy(input, lc_Rn, 8); HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, kdbuf, KD_SIZE, EVP_sha256(), NULL); HMAC_Update(&ctx, input, 8); HMAC_Final(&ctx, res, &resLen); HMAC_CTX_cleanup(&ctx); if (resLen != 32) return -1; memcpy(info->calc_l, res, resLen); return 0; } static int verify_cert(const uint8_t *start) { RSA *rsa = RSA_new(); BIGNUM *e, *m; EVP_PKEY *pRsaKey = EVP_PKEY_new(); EVP_PKEY_CTX *ctx; EVP_MD_CTX *mdctx = NULL; int ret; m = BN_bin2bn(ddccert_m, 384, NULL); e = BN_bin2bn(ddccert_e, 1, NULL); rsa->n = m; rsa->e = e; EVP_PKEY_assign_RSA(pRsaKey, rsa); ctx = EVP_PKEY_CTX_new(pRsaKey, NULL); if (EVP_PKEY_verify_init(ctx) <= 0) { printf("fail 1\n"); return -1; } #if 1 mdctx = EVP_MD_CTX_create(); EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pRsaKey); EVP_DigestVerifyUpdate(mdctx, start, 138); ret = EVP_DigestVerifyFinal(mdctx, start + 138, 384); printf("ret is %d\n", ret); #else if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { printf("fail passing\n"); return; } #if 1 if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) { printf("fail sig\n"); return; } #endif ret = EVP_PKEY_verify(ctx, start + 138, 384, start, 138); #endif printf("ret is %d\n", ret); return ret; } static void decode_cert(struct hdcp_session_info *info, const uint8_t *buf, int len) { const uint8_t *start = buf + 2; int i, ret; info->is_repeater = buf[1] & 0x1; printf("recv id: %02x %02x %02x %02x %02x\n", start[0], start[1], start[2], start[3], start[4]); printf("rect pub key:\n"); for (i = 5; i < 5 + 128; i++) { printf("%02x", start[i]); } printf("\n"); for (i = 133; i < 133 + 3; i++) { printf("%02x", start[i]); } printf("\n"); printf("proto descrip + rsvd: \n"); for (i = 136; i < 136 + 2; i++) { printf("%02x", start[i]); } printf("\nllc sig: \n"); for (i = 138; i < 136 + 384; i++) { printf("%02x", start[i]); } printf("\n"); if (info) { ret = create_gcrypt_pubkey(info, &start[5], &start[133], 128, 3); if (ret != 0) { fprintf(stderr, "failed to create pubkey %d\n", ret); } } ret = verify_cert(start); printf("ret is %d\n", ret); } static void decode_rrx(struct hdcp_session_info *info, const uint8_t *buf, int len) { const uint8_t *start = buf + 1; memcpy(info->rrx, start, 8); } static void decode_h_prime(struct hdcp_session_info *info, const uint8_t *buf, int len) { const uint8_t *start = buf + 1; int i; if (!memcmp(info->calc_h, start, 32)) { info->h_matches = true; printf("H values matched\n"); return; } else { info->h_matches = false; printf("H values failed to match\n"); } printf("h_prime: "); for (i = 0; i < 32; i++) { printf("%02x", start[i]); } printf("\n"); } static void decode_l_prime(struct hdcp_session_info *info, const uint8_t *buf, int len) { const uint8_t *start = buf + 1; int i; if (!memcmp(info->calc_l, start, 32)) { info->l_matches = true; printf("L values matched\n"); return; } else { info->l_matches = false; printf("L values failed to match\n"); } printf("l: "); for (i = 0; i < 32; i++) { printf("%02x", info->calc_l[i]); } printf("\n"); printf("l_prime: "); for (i = 0; i < 32; i++) { printf("%02x", start[i]); } printf("\n"); } static void decode_rx(struct hdcp_session_info *info, const uint8_t *buf, int len) { if (buf[0] != 0 || buf[1] != 0) return; if (buf[4] != 0x4 || buf[7] != 0x80) return; /* hdcp packet */ if (buf[18] != 0x84 && buf[20] != 0x30) return; switch (buf[22]) { case HDCP_AKE_SEND_CERT: decode_cert(info, buf + 22, len - 22); break; case HDCP_AKE_SEND_RRX: decode_rrx(info, buf + 22, len - 22); break; case HDCP_AKE_SEND_H_PRIME: decode_h_prime(info, buf + 22, len - 22); break; case HDCP_AKE_SEND_PAIRING_INFO: printf("send pairing info\n"); break; case HDCP_LC_SEND_L_PRIME: decode_l_prime(info, buf + 22, len - 22); break; case HDCP_REPEATER_AUTH_SEND_RECEIVED_ID_LIST: printf("send received id list\n"); break; } } static int write_to_usb(libusb_device_handle *handle, int endpoint_out, const uint8_t *buf, int len, int *size) { int i = 0, r; do { r = libusb_bulk_transfer(handle, endpoint_out, buf, len, size, 1000); if (r == LIBUSB_ERROR_PIPE) libusb_clear_halt(handle, endpoint_out); i++; } while ((r == LIBUSB_ERROR_PIPE) && (i < 5)); printf("tx: %d:", *size); for (i = 0; i < *size; i++) { printf("%02x ", buf[i]); } printf("\n"); return r; } static int block_read_usb(libusb_device_handle *handle, int endpoint_in, uint8_t *buf, int *size) { int r, i; r = libusb_bulk_transfer(handle, endpoint_in, buf, 1024, size, 1000); if (r < 0) { printf("libusb_bulk_transfer failed: %s\n", libusb_error_name(r)); } printf("rx: %d:", *size); for (i = 0; i < *size; i++) { printf("%02x ", buf[i]); } printf("\n"); return r; } static int dump_buffer(struct hdcp_session_info *info, const uint8_t *buf, int len, int start_input_ctr) { int i, j; uint8_t mybuf[16]; printf("%d: \n", len); for (j = 0; j < len; j += 16) { memset(mybuf, 0, 16); calc_ks_ctr(info, 0x0, start_input_ctr + (j / 16), mybuf, &buf[j]); printf("%d: ", start_input_ctr + (j/16)); for (i = 0; i < 16; i++) { printf("%02x ", mybuf[i]); } printf("\n"); } printf("\n"); } static int test_decode(void) { struct hdcp_session_info info; memset(&info, 0, sizeof(info)); EVP_CIPHER_CTX_init(&info.aes_ctx); info.rtx = Rtx; info.km = forgekm; info.ks = myks2; { dump_buffer(&info, mypkt_enc_data, sizeof(mypkt_enc_data), 0); dump_buffer(&info, mypkt_repl_data, sizeof(mypkt_repl_data), 0); dump_buffer(&info, mypkt_out_data2, sizeof(mypkt_out_data2), 3); dump_buffer(&info, mypkt_repl2_data, sizeof(mypkt_repl2_data), 0x15); } } static int send_buffer(libusb_device_handle *handle, int endpoint_out, int endpoint_in) { unsigned char buf[1024]; int r; int count; int size; int len2, len; gcry_sexp_t km, result; struct hdcp_session_info info; memset(&info, 0, sizeof(info)); EVP_CIPHER_CTX_init(&info.aes_ctx); info.rtx = Rtx; info.km = forgekm; info.ks = myks2; // calculate_hacker_key(&info); // return; dl3_empty_packet(buf, &len); r = write_to_usb(handle, endpoint_out, buf, len, &size); if (r != 0) goto out; dl3_msg2_hdr(buf, &len, 0x25, 0x05, 0x08); r = write_to_usb(handle, endpoint_out, buf, len, &size); if (r != 0) goto out; memset(buf, 0, 1024); dl3_msg2_hdr(buf, &len, 0x04, 0x04, 0x00); len2 = len; dl3_packet_hdcp_ake_init(&buf[len], &len, info.rtx); len2 += len; len2 = ROUND_TO_4(len2); r = write_to_usb(handle, endpoint_out, buf, len2, &size); if (r != 0) goto out; r = block_read_usb(handle, endpoint_in, buf, &size); if (r < 0) goto out; decode_rx(&info, buf, size); r = block_read_usb(handle, endpoint_in, buf, &size); if (r < 0) goto out; decode_rx(&info, buf, size); r = create_gcrypt_km(&km, info.km, 16); if (r != 0) fprintf(stderr, "failed to create km\n"); r = gcry_pk_encrypt(&result, km, info.pub_key); GCRY_SEXP list = gcry_sexp_find_token( result, "a", 0); gcry_mpi_t out_msg = gcry_sexp_nth_mpi(list, 1, GCRYMPI_FMT_USG); gcry_mpi_dump(out_msg); unsigned char obuf[1024] = { 0 }; r = gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char*) &obuf, sizeof(obuf), &size, out_msg); if (r) { printf("failed to stringify mpi"); } dl3_packet_hdcp_ake_no_stored_km(buf, &len, obuf); /* calculate H */ calculate_kd(&info); calculate_h(&info); len = ROUND_TO_4(len); r = write_to_usb(handle, endpoint_out, buf, len, &size); if (r != 0) goto out; count = 4; /* ack, send_Rrx, send_h_prime, send_pairing */ do { r = block_read_usb(handle, endpoint_in, buf, &size); if (r < 0) break; count--; decode_rx(&info, buf, size); if (count == 0) break; /* find H' */ } while (1); if (!info.h_matches) return -1; /* send LC prime */ dl3_packet_hdcp_lc_init(buf, &len, lc_Rn); r = write_to_usb(handle, endpoint_out, buf, len, &size); if (r != 0) goto out; calculate_l(&info); do { r = block_read_usb(handle, endpoint_in, buf, &size); if (r < 0) break; decode_rx(&info, buf, size); /* find L' */ } while (1); if (!info.l_matches) return -1; calculate_edkey_ks(&info); dl3_packet_hdcp_ske_send_eks(buf, &len, info.edkey_ks, riv); r = write_to_usb(handle, endpoint_out, buf, len, &size); if (r != 0) goto out; do { r = block_read_usb(handle, endpoint_in, buf, &size); if (r < 0) break; decode_rx(&info, buf, size); /* find L' */ } while (1); dl3_msg2_hdr(buf, &len, 0x45, 0x05, 0x0e); r = write_to_usb(handle, endpoint_out, buf, len, &size); if (r != 0) goto out; dl3_msg2_hdr(buf, &len, 0x06, 0x04, 0x06); r = write_to_usb(handle, endpoint_out, buf, len, &size); if (r != 0) goto out; dl3_packet_send_enc_data(buf, &len, mypkt_enc_data); r = write_to_usb(handle, endpoint_out, buf, len, &size); if (r != 0) goto out; do { r = block_read_usb(handle, endpoint_in, buf, &size); if (r < 0) break; decode_rx(&info, buf, size); /* find L' */ } while (1); r = 0; out: EVP_CIPHER_CTX_cleanup(&info.aes_ctx); return r; } int test_device(uint16_t vid, uint16_t pid) { libusb_device_handle *handle; libusb_device *dev; uint8_t bus; int r; struct libusb_config_descriptor *conf_desc; int nb_ifaces; int iface; handle = libusb_open_device_with_vid_pid(NULL, vid, pid); if (handle == NULL) { return -1; } dev = libusb_get_device(handle); bus = libusb_get_bus_number(dev); r = libusb_get_config_descriptor(dev, 0, &conf_desc); if (r < 0) return -1; nb_ifaces = conf_desc->bNumInterfaces; libusb_free_config_descriptor(conf_desc); for (iface = 0; iface < nb_ifaces; iface++) { printf("\nClaiming interface %d...\n", iface); r = libusb_claim_interface(handle, iface); if (r != LIBUSB_SUCCESS) { perror(" Failed.\n"); } } printf("num interfaces %d\n", nb_ifaces); send_buffer(handle, 0x02, 0x84); printf("\n"); for (iface = 0; iface