crypto.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. #define D AV_OPT_FLAG_DECODING_PARAM
  45. static const AVOption options[] = {
  46. {"key", "AES decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, .flags = D },
  47. {"iv", "AES decryption initialization vector", OFFSET(iv), AV_OPT_TYPE_BINARY, .flags = D },
  48. { NULL }
  49. };
  50. static const AVClass crypto_class = {
  51. .class_name = "crypto",
  52. .item_name = av_default_item_name,
  53. .option = options,
  54. .version = LIBAVUTIL_VERSION_INT,
  55. };
  56. static int crypto_open(URLContext *h, const char *uri, int flags)
  57. {
  58. const char *nested_url;
  59. int ret = 0;
  60. CryptoContext *c = h->priv_data;
  61. if (!av_strstart(uri, "crypto+", &nested_url) &&
  62. !av_strstart(uri, "crypto:", &nested_url)) {
  63. av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri);
  64. ret = AVERROR(EINVAL);
  65. goto err;
  66. }
  67. if (c->keylen < BLOCKSIZE || c->ivlen < BLOCKSIZE) {
  68. av_log(h, AV_LOG_ERROR, "Key or IV not set\n");
  69. ret = AVERROR(EINVAL);
  70. goto err;
  71. }
  72. if (flags & AVIO_FLAG_WRITE) {
  73. av_log(h, AV_LOG_ERROR, "Only decryption is supported currently\n");
  74. ret = AVERROR(ENOSYS);
  75. goto err;
  76. }
  77. if ((ret = ffurl_open(&c->hd, nested_url, AVIO_FLAG_READ,
  78. &h->interrupt_callback, NULL)) < 0) {
  79. av_log(h, AV_LOG_ERROR, "Unable to open input\n");
  80. goto err;
  81. }
  82. c->aes = av_mallocz(av_aes_size);
  83. if (!c->aes) {
  84. ret = AVERROR(ENOMEM);
  85. goto err;
  86. }
  87. av_aes_init(c->aes, c->key, 128, 1);
  88. h->is_streamed = 1;
  89. err:
  90. return ret;
  91. }
  92. static int crypto_read(URLContext *h, uint8_t *buf, int size)
  93. {
  94. CryptoContext *c = h->priv_data;
  95. int blocks;
  96. retry:
  97. if (c->outdata > 0) {
  98. size = FFMIN(size, c->outdata);
  99. memcpy(buf, c->outptr, size);
  100. c->outptr += size;
  101. c->outdata -= size;
  102. return size;
  103. }
  104. // We avoid using the last block until we've found EOF,
  105. // since we'll remove PKCS7 padding at the end. So make
  106. // sure we've got at least 2 blocks, so we can decrypt
  107. // at least one.
  108. while (c->indata - c->indata_used < 2*BLOCKSIZE) {
  109. int n = ffurl_read(c->hd, c->inbuffer + c->indata,
  110. sizeof(c->inbuffer) - c->indata);
  111. if (n <= 0) {
  112. c->eof = 1;
  113. break;
  114. }
  115. c->indata += n;
  116. }
  117. blocks = (c->indata - c->indata_used) / BLOCKSIZE;
  118. if (!blocks)
  119. return AVERROR_EOF;
  120. if (!c->eof)
  121. blocks--;
  122. av_aes_crypt(c->aes, c->outbuffer, c->inbuffer + c->indata_used, blocks,
  123. c->iv, 1);
  124. c->outdata = BLOCKSIZE * blocks;
  125. c->outptr = c->outbuffer;
  126. c->indata_used += BLOCKSIZE * blocks;
  127. if (c->indata_used >= sizeof(c->inbuffer)/2) {
  128. memmove(c->inbuffer, c->inbuffer + c->indata_used,
  129. c->indata - c->indata_used);
  130. c->indata -= c->indata_used;
  131. c->indata_used = 0;
  132. }
  133. if (c->eof) {
  134. // Remove PKCS7 padding at the end
  135. int padding = c->outbuffer[c->outdata - 1];
  136. c->outdata -= padding;
  137. }
  138. goto retry;
  139. }
  140. static int crypto_close(URLContext *h)
  141. {
  142. CryptoContext *c = h->priv_data;
  143. if (c->hd)
  144. ffurl_close(c->hd);
  145. av_freep(&c->aes);
  146. return 0;
  147. }
  148. URLProtocol ff_crypto_protocol = {
  149. .name = "crypto",
  150. .url_open = crypto_open,
  151. .url_read = crypto_read,
  152. .url_close = crypto_close,
  153. .priv_data_size = sizeof(CryptoContext),
  154. .priv_data_class = &crypto_class,
  155. .flags = URL_PROTOCOL_FLAG_NESTED_SCHEME,
  156. };