pkcs5.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * PKCS #5 (Password-based Encryption)
  3. * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "crypto/crypto.h"
  17. #include "crypto/md5.h"
  18. #include "asn1.h"
  19. #include "pkcs5.h"
  20. struct pkcs5_params {
  21. enum pkcs5_alg {
  22. PKCS5_ALG_UNKNOWN,
  23. PKCS5_ALG_MD5_DES_CBC
  24. } alg;
  25. u8 salt[8];
  26. size_t salt_len;
  27. unsigned int iter_count;
  28. };
  29. static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
  30. {
  31. if (oid->len == 7 &&
  32. oid->oid[0] == 1 /* iso */ &&
  33. oid->oid[1] == 2 /* member-body */ &&
  34. oid->oid[2] == 840 /* us */ &&
  35. oid->oid[3] == 113549 /* rsadsi */ &&
  36. oid->oid[4] == 1 /* pkcs */ &&
  37. oid->oid[5] == 5 /* pkcs-5 */ &&
  38. oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
  39. return PKCS5_ALG_MD5_DES_CBC;
  40. return PKCS5_ALG_UNKNOWN;
  41. }
  42. static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
  43. struct pkcs5_params *params)
  44. {
  45. struct asn1_hdr hdr;
  46. const u8 *enc_alg_end, *pos, *end;
  47. struct asn1_oid oid;
  48. char obuf[80];
  49. /* AlgorithmIdentifier */
  50. enc_alg_end = enc_alg + enc_alg_len;
  51. os_memset(params, 0, sizeof(*params));
  52. if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) {
  53. wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID "
  54. "(algorithm)");
  55. return -1;
  56. }
  57. asn1_oid_to_str(&oid, obuf, sizeof(obuf));
  58. wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf);
  59. params->alg = pkcs5_get_alg(&oid);
  60. if (params->alg == PKCS5_ALG_UNKNOWN) {
  61. wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption "
  62. "algorithm %s", obuf);
  63. return -1;
  64. }
  65. /*
  66. * PKCS#5, Section 8
  67. * PBEParameter ::= SEQUENCE {
  68. * salt OCTET STRING SIZE(8),
  69. * iterationCount INTEGER }
  70. */
  71. if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
  72. hdr.class != ASN1_CLASS_UNIVERSAL ||
  73. hdr.tag != ASN1_TAG_SEQUENCE) {
  74. wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
  75. "(PBEParameter) - found class %d tag 0x%x",
  76. hdr.class, hdr.tag);
  77. return -1;
  78. }
  79. pos = hdr.payload;
  80. end = hdr.payload + hdr.length;
  81. /* salt OCTET STRING SIZE(8) */
  82. if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
  83. hdr.class != ASN1_CLASS_UNIVERSAL ||
  84. hdr.tag != ASN1_TAG_OCTETSTRING ||
  85. hdr.length != 8) {
  86. wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
  87. "(salt) - found class %d tag 0x%x size %d",
  88. hdr.class, hdr.tag, hdr.length);
  89. return -1;
  90. }
  91. pos = hdr.payload + hdr.length;
  92. os_memcpy(params->salt, hdr.payload, hdr.length);
  93. params->salt_len = hdr.length;
  94. wpa_hexdump(MSG_DEBUG, "PKCS #5: salt",
  95. params->salt, params->salt_len);
  96. /* iterationCount INTEGER */
  97. if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
  98. hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
  99. wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found "
  100. "class %d tag 0x%x", hdr.class, hdr.tag);
  101. return -1;
  102. }
  103. if (hdr.length == 1)
  104. params->iter_count = *hdr.payload;
  105. else if (hdr.length == 2)
  106. params->iter_count = WPA_GET_BE16(hdr.payload);
  107. else if (hdr.length == 4)
  108. params->iter_count = WPA_GET_BE32(hdr.payload);
  109. else {
  110. wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value "
  111. " (iterationCount)",
  112. hdr.payload, hdr.length);
  113. return -1;
  114. }
  115. wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
  116. params->iter_count);
  117. if (params->iter_count == 0 || params->iter_count > 0xffff) {
  118. wpa_printf(MSG_INFO, "PKCS #5: Unsupported "
  119. "iterationCount=0x%x", params->iter_count);
  120. return -1;
  121. }
  122. return 0;
  123. }
  124. static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
  125. const char *passwd)
  126. {
  127. unsigned int i;
  128. u8 hash[MD5_MAC_LEN];
  129. const u8 *addr[2];
  130. size_t len[2];
  131. if (params->alg != PKCS5_ALG_MD5_DES_CBC)
  132. return NULL;
  133. addr[0] = (const u8 *) passwd;
  134. len[0] = os_strlen(passwd);
  135. addr[1] = params->salt;
  136. len[1] = params->salt_len;
  137. if (md5_vector(2, addr, len, hash) < 0)
  138. return NULL;
  139. addr[0] = hash;
  140. len[0] = MD5_MAC_LEN;
  141. for (i = 1; i < params->iter_count; i++) {
  142. if (md5_vector(1, addr, len, hash) < 0)
  143. return NULL;
  144. }
  145. /* TODO: DES key parity bits(?) */
  146. wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8);
  147. wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
  148. return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
  149. }
  150. u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
  151. const u8 *enc_data, size_t enc_data_len,
  152. const char *passwd, size_t *data_len)
  153. {
  154. struct crypto_cipher *ctx;
  155. u8 *eb, pad;
  156. struct pkcs5_params params;
  157. unsigned int i;
  158. if (pkcs5_get_params(enc_alg, enc_alg_len, &params) < 0) {
  159. wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters");
  160. return NULL;
  161. }
  162. ctx = pkcs5_crypto_init(&params, passwd);
  163. if (ctx == NULL) {
  164. wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
  165. return NULL;
  166. }
  167. /* PKCS #5, Section 7 - Decryption process */
  168. if (enc_data_len < 16 || enc_data_len % 8) {
  169. wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext "
  170. "%d", (int) enc_data_len);
  171. crypto_cipher_deinit(ctx);
  172. return NULL;
  173. }
  174. eb = os_malloc(enc_data_len);
  175. if (eb == NULL) {
  176. crypto_cipher_deinit(ctx);
  177. return NULL;
  178. }
  179. if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
  180. wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
  181. crypto_cipher_deinit(ctx);
  182. os_free(eb);
  183. return NULL;
  184. }
  185. crypto_cipher_deinit(ctx);
  186. pad = eb[enc_data_len - 1];
  187. if (pad > 8) {
  188. wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad);
  189. os_free(eb);
  190. return NULL;
  191. }
  192. for (i = enc_data_len - pad; i < enc_data_len; i++) {
  193. if (eb[i] != pad) {
  194. wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS",
  195. eb + enc_data_len - pad, pad);
  196. os_free(eb);
  197. return NULL;
  198. }
  199. }
  200. wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)",
  201. eb, enc_data_len - pad);
  202. *data_len = enc_data_len - pad;
  203. return eb;
  204. }