crypto.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Decryption protocol handler
  3. * Copyright (c) 2011 Martin Storsjo
  4. *
  5. * This file is part of Libav.
  6. *
  7. * Libav is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * Libav is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with Libav; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avformat.h"
  22. #include "libavutil/aes.h"
  23. #include "libavutil/avstring.h"
  24. #include "libavutil/opt.h"
  25. #include "internal.h"
  26. #include "url.h"
  27. #define MAX_BUFFER_BLOCKS 150
  28. #define BLOCKSIZE 16
  29. typedef struct {
  30. const AVClass *class;
  31. URLContext *hd;
  32. uint8_t inbuffer [BLOCKSIZE*MAX_BUFFER_BLOCKS],
  33. outbuffer[BLOCKSIZE*MAX_BUFFER_BLOCKS];
  34. uint8_t *outptr;
  35. int indata, indata_used, outdata;
  36. int eof;
  37. uint8_t *key;
  38. int keylen;
  39. uint8_t *iv;
  40. int ivlen;
  41. struct AVAES *aes;
  42. } CryptoContext;
  43. #define OFFSET(x) offsetof(CryptoContext, x)
  44. static const AVOption options[] = {
  45. {"key", "AES decryption key", OFFSET(key), FF_OPT_TYPE_BINARY },
  46. {"iv", "AES decryption initialization vector", OFFSET(iv), FF_OPT_TYPE_BINARY },
  47. { NULL }
  48. };
  49. static const AVClass crypto_class = {
  50. .class_name = "crypto",
  51. .item_name = av_default_item_name,
  52. .option = options,
  53. .version = LIBAVUTIL_VERSION_INT,
  54. };
  55. static int crypto_open(URLContext *h, const char *uri, int flags)
  56. {
  57. const char *nested_url;
  58. int ret;
  59. CryptoContext *c = h->priv_data;
  60. if (!av_strstart(uri, "crypto+", &nested_url) &&
  61. !av_strstart(uri, "crypto:", &nested_url)) {
  62. av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri);
  63. ret = AVERROR(EINVAL);
  64. goto err;
  65. }
  66. if (c->keylen < BLOCKSIZE || c->ivlen < BLOCKSIZE) {
  67. av_log(h, AV_LOG_ERROR, "Key or IV not set\n");
  68. ret = AVERROR(EINVAL);
  69. goto err;
  70. }
  71. if (flags == AVIO_WRONLY) {
  72. av_log(h, AV_LOG_ERROR, "Only decryption is supported currently\n");
  73. ret = AVERROR(ENOSYS);
  74. goto err;
  75. }
  76. if ((ret = ffurl_open(&c->hd, nested_url, AVIO_RDONLY)) < 0) {
  77. av_log(h, AV_LOG_ERROR, "Unable to open input\n");
  78. goto err;
  79. }
  80. c->aes = av_mallocz(av_aes_size);
  81. if (!c->aes) {
  82. ret = AVERROR(ENOMEM);
  83. goto err;
  84. }
  85. av_aes_init(c->aes, c->key, 128, 1);
  86. h->is_streamed = 1;
  87. return 0;
  88. err:
  89. av_freep(&c->key);
  90. av_freep(&c->iv);
  91. return ret;
  92. }
  93. static int crypto_read(URLContext *h, uint8_t *buf, int size)
  94. {
  95. CryptoContext *c = h->priv_data;
  96. int blocks;
  97. retry:
  98. if (c->outdata > 0) {
  99. size = FFMIN(size, c->outdata);
  100. memcpy(buf, c->outptr, size);
  101. c->outptr += size;
  102. c->outdata -= size;
  103. return size;
  104. }
  105. // We avoid using the last block until we've found EOF,
  106. // since we'll remove PKCS7 padding at the end. So make
  107. // sure we've got at least 2 blocks, so we can decrypt
  108. // at least one.
  109. while (c->indata - c->indata_used < 2*BLOCKSIZE) {
  110. int n = ffurl_read(c->hd, c->inbuffer + c->indata,
  111. sizeof(c->inbuffer) - c->indata);
  112. if (n <= 0) {
  113. c->eof = 1;
  114. break;
  115. }
  116. c->indata += n;
  117. }
  118. blocks = (c->indata - c->indata_used) / BLOCKSIZE;
  119. if (!blocks)
  120. return AVERROR_EOF;
  121. if (!c->eof)
  122. blocks--;
  123. av_aes_crypt(c->aes, c->outbuffer, c->inbuffer + c->indata_used, blocks,
  124. c->iv, 1);
  125. c->outdata = BLOCKSIZE * blocks;
  126. c->outptr = c->outbuffer;
  127. c->indata_used += BLOCKSIZE * blocks;
  128. if (c->indata_used >= sizeof(c->inbuffer)/2) {
  129. memmove(c->inbuffer, c->inbuffer + c->indata_used,
  130. c->indata - c->indata_used);
  131. c->indata -= c->indata_used;
  132. c->indata_used = 0;
  133. }
  134. if (c->eof) {
  135. // Remove PKCS7 padding at the end
  136. int padding = c->outbuffer[c->outdata - 1];
  137. c->outdata -= padding;
  138. }
  139. goto retry;
  140. }
  141. static int crypto_close(URLContext *h)
  142. {
  143. CryptoContext *c = h->priv_data;
  144. if (c->hd)
  145. ffurl_close(c->hd);
  146. av_freep(&c->aes);
  147. av_freep(&c->key);
  148. av_freep(&c->iv);
  149. return 0;
  150. }
  151. URLProtocol ff_crypto_protocol = {
  152. .name = "crypto",
  153. .url_open = crypto_open,
  154. .url_read = crypto_read,
  155. .url_close = crypto_close,
  156. .priv_data_size = sizeof(CryptoContext),
  157. .priv_data_class = &crypto_class,
  158. .flags = URL_PROTOCOL_FLAG_NESTED_SCHEME,
  159. };