e_rc4_hmac_md5.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* ====================================================================
  2. * Copyright (c) 2011 The OpenSSL Project. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in
  13. * the documentation and/or other materials provided with the
  14. * distribution.
  15. *
  16. * 3. All advertising materials mentioning features or use of this
  17. * software must display the following acknowledgment:
  18. * "This product includes software developed by the OpenSSL Project
  19. * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
  20. *
  21. * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  22. * endorse or promote products derived from this software without
  23. * prior written permission. For written permission, please contact
  24. * licensing@OpenSSL.org.
  25. *
  26. * 5. Products derived from this software may not be called "OpenSSL"
  27. * nor may "OpenSSL" appear in their names without prior written
  28. * permission of the OpenSSL Project.
  29. *
  30. * 6. Redistributions of any form whatsoever must retain the following
  31. * acknowledgment:
  32. * "This product includes software developed by the OpenSSL Project
  33. * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
  34. *
  35. * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  36. * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46. * OF THE POSSIBILITY OF SUCH DAMAGE.
  47. * ====================================================================
  48. */
  49. #include <openssl/opensslconf.h>
  50. #include <stdio.h>
  51. #include <string.h>
  52. #if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5)
  53. #include <openssl/evp.h>
  54. #include <openssl/objects.h>
  55. #include <openssl/rc4.h>
  56. #include <openssl/md5.h>
  57. #ifndef EVP_CIPH_FLAG_AEAD_CIPHER
  58. #define EVP_CIPH_FLAG_AEAD_CIPHER 0x200000
  59. #define EVP_CTRL_AEAD_TLS1_AAD 0x16
  60. #define EVP_CTRL_AEAD_SET_MAC_KEY 0x17
  61. #endif
  62. /* FIXME: surely this is available elsewhere? */
  63. #define EVP_RC4_KEY_SIZE 16
  64. typedef struct
  65. {
  66. RC4_KEY ks;
  67. MD5_CTX head,tail,md;
  68. size_t payload_length;
  69. } EVP_RC4_HMAC_MD5;
  70. void rc4_md5_enc (RC4_KEY *key, const void *in0, void *out,
  71. MD5_CTX *ctx,const void *inp,size_t blocks);
  72. #define data(ctx) ((EVP_RC4_HMAC_MD5 *)(ctx)->cipher_data)
  73. static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX *ctx,
  74. const unsigned char *inkey,
  75. const unsigned char *iv, int enc)
  76. {
  77. EVP_RC4_HMAC_MD5 *key = data(ctx);
  78. RC4_set_key(&key->ks,EVP_CIPHER_CTX_key_length(ctx),
  79. inkey);
  80. MD5_Init(&key->head); /* handy when benchmarking */
  81. key->tail = key->head;
  82. key->md = key->head;
  83. key->payload_length = 0;
  84. return 1;
  85. }
  86. #if !defined(OPENSSL_NO_ASM) && ( \
  87. defined(__x86_64) || defined(__x86_64__) || \
  88. defined(_M_AMD64) || defined(_M_X64) || \
  89. defined(__INTEL__) )
  90. #define STITCHED_CALL
  91. #endif
  92. #if !defined(STITCHED_CALL)
  93. #define rc4_off 0
  94. #define md5_off 0
  95. #endif
  96. static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
  97. const unsigned char *in, size_t len)
  98. {
  99. EVP_RC4_HMAC_MD5 *key = data(ctx);
  100. #if defined(STITCHED_CALL)
  101. size_t rc4_off = 32-1-(key->ks.x&(32-1)), /* 32 is $MOD from rc4_md5-x86_64.pl */
  102. md5_off = MD5_CBLOCK-key->md.num,
  103. blocks;
  104. unsigned int l;
  105. #endif
  106. size_t plen = key->payload_length;
  107. if (plen && len!=(plen+MD5_DIGEST_LENGTH)) return 0;
  108. if (ctx->encrypt) {
  109. if (plen==0) plen = len;
  110. #if defined(STITCHED_CALL)
  111. /* cipher has to "fall behind" */
  112. if (rc4_off>md5_off) md5_off+=MD5_CBLOCK;
  113. if (plen>md5_off && (blocks=(plen-md5_off)/MD5_CBLOCK)) {
  114. MD5_Update(&key->md,in,md5_off);
  115. RC4(&key->ks,rc4_off,in,out);
  116. rc4_md5_enc(&key->ks,in+rc4_off,out+rc4_off,
  117. &key->md,in+md5_off,blocks);
  118. blocks *= MD5_CBLOCK;
  119. rc4_off += blocks;
  120. md5_off += blocks;
  121. key->md.Nh += blocks>>29;
  122. key->md.Nl += blocks<<=3;
  123. if (key->md.Nl<(unsigned int)blocks) key->md.Nh++;
  124. } else {
  125. rc4_off = 0;
  126. md5_off = 0;
  127. }
  128. #endif
  129. MD5_Update(&key->md,in+md5_off,plen-md5_off);
  130. if (plen!=len) { /* "TLS" mode of operation */
  131. if (in!=out)
  132. memcpy(out+rc4_off,in+rc4_off,plen-rc4_off);
  133. /* calculate HMAC and append it to payload */
  134. MD5_Final(out+plen,&key->md);
  135. key->md = key->tail;
  136. MD5_Update(&key->md,out+plen,MD5_DIGEST_LENGTH);
  137. MD5_Final(out+plen,&key->md);
  138. /* encrypt HMAC at once */
  139. RC4(&key->ks,len-rc4_off,out+rc4_off,out+rc4_off);
  140. } else {
  141. RC4(&key->ks,len-rc4_off,in+rc4_off,out+rc4_off);
  142. }
  143. } else {
  144. unsigned char mac[MD5_DIGEST_LENGTH];
  145. #if defined(STITCHED_CALL)
  146. /* digest has to "fall behind" */
  147. if (md5_off>rc4_off) rc4_off += 2*MD5_CBLOCK;
  148. else rc4_off += MD5_CBLOCK;
  149. if (len>rc4_off && (blocks=(len-rc4_off)/MD5_CBLOCK)) {
  150. RC4(&key->ks,rc4_off,in,out);
  151. MD5_Update(&key->md,out,md5_off);
  152. rc4_md5_enc(&key->ks,in+rc4_off,out+rc4_off,
  153. &key->md,out+md5_off,blocks);
  154. blocks *= MD5_CBLOCK;
  155. rc4_off += blocks;
  156. md5_off += blocks;
  157. l = (key->md.Nl+(blocks<<3))&0xffffffffU;
  158. if (l<key->md.Nl) key->md.Nh++;
  159. key->md.Nl = l;
  160. key->md.Nh += blocks>>29;
  161. } else {
  162. md5_off=0;
  163. rc4_off=0;
  164. }
  165. #endif
  166. /* decrypt HMAC at once */
  167. RC4(&key->ks,len-rc4_off,in+rc4_off,out+rc4_off);
  168. if (plen) { /* "TLS" mode of operation */
  169. MD5_Update(&key->md,out+md5_off,plen-md5_off);
  170. /* calculate HMAC and verify it */
  171. MD5_Final(mac,&key->md);
  172. key->md = key->tail;
  173. MD5_Update(&key->md,mac,MD5_DIGEST_LENGTH);
  174. MD5_Final(mac,&key->md);
  175. if (memcmp(out+plen,mac,MD5_DIGEST_LENGTH))
  176. return 0;
  177. } else {
  178. MD5_Update(&key->md,out+md5_off,len-md5_off);
  179. }
  180. }
  181. key->payload_length = 0;
  182. return 1;
  183. }
  184. static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
  185. {
  186. EVP_RC4_HMAC_MD5 *key = data(ctx);
  187. switch (type)
  188. {
  189. case EVP_CTRL_AEAD_SET_MAC_KEY:
  190. {
  191. unsigned int i;
  192. unsigned char hmac_key[64];
  193. memset (hmac_key,0,sizeof(hmac_key));
  194. if (arg > (int)sizeof(hmac_key)) {
  195. MD5_Init(&key->head);
  196. MD5_Update(&key->head,ptr,arg);
  197. MD5_Final(hmac_key,&key->head);
  198. } else {
  199. memcpy(hmac_key,ptr,arg);
  200. }
  201. for (i=0;i<sizeof(hmac_key);i++)
  202. hmac_key[i] ^= 0x36; /* ipad */
  203. MD5_Init(&key->head);
  204. MD5_Update(&key->head,hmac_key,sizeof(hmac_key));
  205. for (i=0;i<sizeof(hmac_key);i++)
  206. hmac_key[i] ^= 0x36^0x5c; /* opad */
  207. MD5_Init(&key->tail);
  208. MD5_Update(&key->tail,hmac_key,sizeof(hmac_key));
  209. return 1;
  210. }
  211. case EVP_CTRL_AEAD_TLS1_AAD:
  212. {
  213. unsigned char *p=ptr;
  214. unsigned int len=p[arg-2]<<8|p[arg-1];
  215. if (!ctx->encrypt)
  216. {
  217. len -= MD5_DIGEST_LENGTH;
  218. p[arg-2] = len>>8;
  219. p[arg-1] = len;
  220. }
  221. key->payload_length=len;
  222. key->md = key->head;
  223. MD5_Update(&key->md,p,arg);
  224. return MD5_DIGEST_LENGTH;
  225. }
  226. default:
  227. return -1;
  228. }
  229. }
  230. static EVP_CIPHER r4_hmac_md5_cipher=
  231. {
  232. #ifdef NID_rc4_hmac_md5
  233. NID_rc4_hmac_md5,
  234. #else
  235. NID_undef,
  236. #endif
  237. 1,EVP_RC4_KEY_SIZE,0,
  238. EVP_CIPH_STREAM_CIPHER|EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_FLAG_AEAD_CIPHER,
  239. rc4_hmac_md5_init_key,
  240. rc4_hmac_md5_cipher,
  241. NULL,
  242. sizeof(EVP_RC4_HMAC_MD5),
  243. NULL,
  244. NULL,
  245. rc4_hmac_md5_ctrl,
  246. NULL
  247. };
  248. const EVP_CIPHER *EVP_rc4_hmac_md5(void)
  249. {
  250. return(&r4_hmac_md5_cipher);
  251. }
  252. #endif