static void encrypt_counter(struct AVAES *aes, uint8_t *iv, uint8_t *outbuf, int outlen) { int i, j, outpos; for (i = 0, outpos = 0; outpos < outlen; i++) { uint8_t keystream[16]; AV_WB16(&iv[14], i); av_aes_crypt(aes, keystream, iv, 1, NULL, 0); for (j = 0; j < 16 && outpos < outlen; j++, outpos++) outbuf[outpos] ^= keystream[j]; } }
static int crypto_write(URLContext *h, const unsigned char *buf, int size) { CryptoContext *c = h->priv_data; int total_size, blocks, pad_len, out_size; uint8_t *out_buf; int ret = 0; total_size = size + c->pad_len; pad_len = total_size % BLOCKSIZE; out_size = total_size - pad_len; blocks = out_size / BLOCKSIZE; if (out_size) { out_buf = av_malloc(out_size); if (!out_buf) return AVERROR(ENOMEM); if (c->pad_len) { memcpy(&c->pad[c->pad_len], buf, BLOCKSIZE - c->pad_len); av_aes_crypt(c->aes_encrypt, out_buf, c->pad, 1, c->encrypt_iv, 0); blocks--; } av_aes_crypt(c->aes_encrypt, &out_buf[c->pad_len ? BLOCKSIZE : 0], &buf[c->pad_len ? BLOCKSIZE - c->pad_len: 0], blocks, c->encrypt_iv, 0); ret = ffurl_write(c->hd, out_buf, out_size); av_free(out_buf); if (ret < 0) return ret; memcpy(c->pad, &buf[size - pad_len], pad_len); } else memcpy(&c->pad[c->pad_len], buf, size); c->pad_len = pad_len; return size; }
static int crypto_read(URLContext *h, uint8_t *buf, int size) { CryptoContext *c = h->priv_data; int blocks; retry: if (c->outdata > 0) { size = FFMIN(size, c->outdata); memcpy(buf, c->outptr, size); c->outptr += size; c->outdata -= size; c->position = c->position + size; return size; } // We avoid using the last block until we've found EOF, // since we'll remove PKCS7 padding at the end. So make // sure we've got at least 2 blocks, so we can decrypt // at least one. while (c->indata - c->indata_used < 2*BLOCKSIZE) { int n = ffurl_read(c->hd, c->inbuffer + c->indata, sizeof(c->inbuffer) - c->indata); if (n <= 0) { c->eof = 1; break; } c->indata += n; } blocks = (c->indata - c->indata_used) / BLOCKSIZE; if (!blocks) return AVERROR_EOF; if (!c->eof) blocks--; av_aes_crypt(c->aes_decrypt, c->outbuffer, c->inbuffer + c->indata_used, blocks, c->decrypt_iv, 1); c->outdata = BLOCKSIZE * blocks; c->outptr = c->outbuffer; c->indata_used += BLOCKSIZE * blocks; if (c->indata_used >= sizeof(c->inbuffer)/2) { memmove(c->inbuffer, c->inbuffer + c->indata_used, c->indata - c->indata_used); c->indata -= c->indata_used; c->indata_used = 0; } if (c->eof) { // Remove PKCS7 padding at the end int padding = c->outbuffer[c->outdata - 1]; c->outdata -= padding; } goto retry; }
static int crypto_close(URLContext *h) { CryptoContext *c = h->priv_data; uint8_t out_buf[BLOCKSIZE]; int ret, pad; if (c->aes_encrypt) { pad = BLOCKSIZE - c->pad_len; memset(&c->pad[c->pad_len], pad, pad); av_aes_crypt(c->aes_encrypt, out_buf, c->pad, 1, c->encrypt_iv, 0); if ((ret = ffurl_write(c->hd, out_buf, BLOCKSIZE)) < 0) return ret; } if (c->hd) ffurl_close(c->hd); av_freep(&c->aes_decrypt); av_freep(&c->aes_encrypt); return 0; }
static int list_read(URLContext *h, unsigned char *buf, int size) { struct list_mgt *mgt = h->priv_data; int len=AVERROR(EIO); struct list_item *item=mgt->current_item; int retries = 10; retry: if (url_interrupt_cb()){ av_log(NULL, AV_LOG_ERROR," url_interrupt_cb\n"); return AVERROR(EINTR); } //av_log(NULL, AV_LOG_INFO, "list_read start buf=%x,size=%d\n",buf,size); if(!mgt->cur_uio ) { if(item && item->file) { ByteIOContext *bio; av_log(NULL, AV_LOG_INFO, "list_read switch to new file=%s\n",item->file); len=url_fopen(&bio,item->file,AVIO_FLAG_READ | URL_MINI_BUFFER | URL_NO_LP_BUFFER); if(len!=0) { av_log(NULL, AV_LOG_ERROR, "list url_fopen failed =%d\n",len); return len; } if(url_is_file_list(bio,item->file)) { mgt->have_sub_list = 1; /*have 32 bytes space at the end..*/ memmove(item->file+5,item->file,strlen(item->file)+1); memcpy(item->file,"list:",5); url_fclose(bio); len=url_fopen(&bio,item->file,mgt->flags | URL_MINI_BUFFER | URL_NO_LP_BUFFER); if(len!=0) { av_log(NULL, AV_LOG_INFO, "file list url_fopen failed =%d\n",len); return len; } }else{ if(item->ktype == KEY_AES_128){ if(item->key_ctx&&!item->crypto){ item->crypto = av_mallocz(sizeof(struct AESCryptoContext)); if(!item->crypto){ len = AVERROR(ENOMEM); return len; } item->crypto->aes = av_mallocz(av_aes_size); if(!item->crypto->aes){ len = AVERROR(ENOMEM); return len; } av_aes_init(item->crypto->aes,item->key_ctx->key, 128, 1); item->crypto->have_init = 1; } bio->is_encrypted_media =1; } } mgt->cur_uio=bio; } } if(mgt->cur_uio){ if(size>0&&mgt->cur_uio->is_encrypted_media>0&&mgt->current_item->key_ctx&&mgt->current_item->crypto){//codes from crypto.c int blocks; struct AESCryptoContext* c = mgt->current_item->crypto; readagain: len = 0; if (c->outdata > 0) { size = FFMIN(size, c->outdata); memcpy(buf, c->outptr, size); c->outptr += size; c->outdata -= size; len =size; } // We avoid using the last block until we've found EOF, // since we'll remove PKCS7 padding at the end. So make // sure we've got at least 2 blocks, so we can decrypt // at least one. while (c->indata - c->indata_used < 2*BLOCKSIZE) { int n = get_buffer(mgt->cur_uio,c->inbuffer + c->indata, sizeof(c->inbuffer) - c->indata); if (n <= 0) { c->eof = 1; break; } c->indata += n; } blocks = (c->indata - c->indata_used) / BLOCKSIZE; if (blocks!=0){ if (!c->eof) blocks--; av_aes_crypt(c->aes, c->outbuffer, c->inbuffer + c->indata_used, blocks,mgt->current_item->key_ctx->iv, 1); c->outdata = BLOCKSIZE * blocks; c->outptr = c->outbuffer; c->indata_used += BLOCKSIZE * blocks; if (c->indata_used >= sizeof(c->inbuffer)/2) { memmove(c->inbuffer, c->inbuffer + c->indata_used, c->indata - c->indata_used); c->indata -= c->indata_used; c->indata_used = 0; } if (c->eof) { // Remove PKCS7 padding at the end int padding = c->outbuffer[c->outdata - 1]; c->outdata -= padding; } if(len==0){ goto readagain; } }else{ len =0; } }else{ len=get_buffer(mgt->cur_uio,buf,size); } //av_log(NULL, AV_LOG_INFO, "list_read get_buffer=%d\n",len); } if(len==AVERROR(EAGAIN)) return AVERROR(EAGAIN);/*not end,bug need to*/ else if((len<=0)&& mgt->current_item!=NULL) {/*end of the file*/ av_log(NULL, AV_LOG_INFO, "try switchto_next_item buf=%x,size=%d,len=%d\n",buf,size,len); if(item && (item->flags & ENDLIST_FLAG)){ if(mgt->cur_uio) url_fclose(mgt->cur_uio); av_log(NULL, AV_LOG_INFO, "ENDLIST_FLAG, return 0\n"); return 0; } item=switchto_next_item(mgt); if(!item){ if(mgt->flags&REAL_STREAMING_FLAG){ fresh_item_list(mgt); if(retries>0){ retries --; goto retry; } } av_log(NULL, AV_LOG_INFO, "Need more retry by player logic\n"); return AVERROR(EAGAIN);/*not end,but need to refresh the list later*/ } if(mgt->cur_uio) url_fclose(mgt->cur_uio); mgt->cur_uio=NULL; mgt->current_item=item; if(item->flags & ENDLIST_FLAG){ av_log(NULL, AV_LOG_INFO, "reach list end now!,item=%x\n",item); return 0;/*endof file*/ } else if(item->flags & DISCONTINUE_FLAG){ av_log(NULL, AV_LOG_INFO, "Discontiue item \n"); //1 TODO:need to notify uper level stream is changed goto retry; } else{ av_log(NULL, AV_LOG_INFO, "[%s]item->flags=%x \n", __FUNCTION__, item->flags); goto retry; } } #if 0 if(mgt->flags&REAL_STREAMING_FLAG&&mgt->item_num<4){ //force refresh items fresh_item_list(mgt); } #endif //av_log(NULL, AV_LOG_INFO, "list_read end buf=%x,size=%d return len=%x\n",buf,size,len); return len; }
int main(int argc, char **argv) { int i, j; AVAES b; static const uint8_t rkey[2][16] = { { 0 }, { 0x10, 0xa5, 0x88, 0x69, 0xd7, 0x4b, 0xe5, 0xa3, 0x74, 0xcf, 0x86, 0x7c, 0xfb, 0x47, 0x38, 0x59 } }; static const uint8_t rpt[2][16] = { { 0x6a, 0x84, 0x86, 0x7c, 0xd7, 0x7e, 0x12, 0xad, 0x07, 0xea, 0x1b, 0xe8, 0x95, 0xc5, 0x3f, 0xa3 }, { 0 } }; static const uint8_t rct[2][16] = { { 0x73, 0x22, 0x81, 0xc0, 0xa0, 0xaa, 0xb8, 0xf7, 0xa5, 0x4a, 0x0c, 0x67, 0xa0, 0xc4, 0x5e, 0xcf }, { 0x6d, 0x25, 0x1e, 0x69, 0x44, 0xb0, 0x51, 0xe0, 0x4e, 0xaa, 0x6f, 0xb4, 0xdb, 0xf7, 0x84, 0x65 } }; uint8_t pt[16], temp[16]; int err = 0; av_log_set_level(AV_LOG_DEBUG); for (i = 0; i < 2; i++) { av_aes_init(&b, rkey[i], 128, 1); av_aes_crypt(&b, temp, rct[i], 1, NULL, 1); for (j = 0; j < 16; j++) { if (rpt[i][j] != temp[j]) { av_log(NULL, AV_LOG_ERROR, "%d %02X %02X\n", j, rpt[i][j], temp[j]); err = 1; } } } if (argc > 1 && !strcmp(argv[1], "-t")) { AVAES ae, ad; AVLFG prng; av_aes_init(&ae, "PI=3.141592654..", 128, 0); av_aes_init(&ad, "PI=3.141592654..", 128, 1); av_lfg_init(&prng, 1); for (i = 0; i < 10000; i++) { for (j = 0; j < 16; j++) pt[j] = av_lfg_get(&prng); { START_TIMER; av_aes_crypt(&ae, temp, pt, 1, NULL, 0); if (!(i & (i - 1))) av_log(NULL, AV_LOG_ERROR, "%02X %02X %02X %02X\n", temp[0], temp[5], temp[10], temp[15]); av_aes_crypt(&ad, temp, temp, 1, NULL, 1); STOP_TIMER("aes"); } for (j = 0; j < 16; j++) { if (pt[j] != temp[j]) { av_log(NULL, AV_LOG_ERROR, "%d %d %02X %02X\n", i, j, pt[j], temp[j]); } } } } return err; }