1214501Srpaulo/* 2214501Srpaulo * PKCS #5 (Password-based Encryption) 3214501Srpaulo * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "crypto/crypto.h" 13214501Srpaulo#include "crypto/md5.h" 14214501Srpaulo#include "asn1.h" 15214501Srpaulo#include "pkcs5.h" 16214501Srpaulo 17214501Srpaulo 18214501Srpaulostruct pkcs5_params { 19214501Srpaulo enum pkcs5_alg { 20214501Srpaulo PKCS5_ALG_UNKNOWN, 21214501Srpaulo PKCS5_ALG_MD5_DES_CBC 22214501Srpaulo } alg; 23214501Srpaulo u8 salt[8]; 24214501Srpaulo size_t salt_len; 25214501Srpaulo unsigned int iter_count; 26214501Srpaulo}; 27214501Srpaulo 28214501Srpaulo 29252726Srpaulostatic enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) 30214501Srpaulo{ 31214501Srpaulo if (oid->len == 7 && 32214501Srpaulo oid->oid[0] == 1 /* iso */ && 33214501Srpaulo oid->oid[1] == 2 /* member-body */ && 34214501Srpaulo oid->oid[2] == 840 /* us */ && 35214501Srpaulo oid->oid[3] == 113549 /* rsadsi */ && 36214501Srpaulo oid->oid[4] == 1 /* pkcs */ && 37214501Srpaulo oid->oid[5] == 5 /* pkcs-5 */ && 38214501Srpaulo oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */) 39214501Srpaulo return PKCS5_ALG_MD5_DES_CBC; 40214501Srpaulo 41214501Srpaulo return PKCS5_ALG_UNKNOWN; 42214501Srpaulo} 43214501Srpaulo 44214501Srpaulo 45214501Srpaulostatic int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len, 46214501Srpaulo struct pkcs5_params *params) 47214501Srpaulo{ 48214501Srpaulo struct asn1_hdr hdr; 49214501Srpaulo const u8 *enc_alg_end, *pos, *end; 50214501Srpaulo struct asn1_oid oid; 51214501Srpaulo char obuf[80]; 52214501Srpaulo 53214501Srpaulo /* AlgorithmIdentifier */ 54214501Srpaulo 55214501Srpaulo enc_alg_end = enc_alg + enc_alg_len; 56214501Srpaulo 57214501Srpaulo os_memset(params, 0, sizeof(*params)); 58214501Srpaulo 59214501Srpaulo if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) { 60214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID " 61214501Srpaulo "(algorithm)"); 62214501Srpaulo return -1; 63214501Srpaulo } 64214501Srpaulo 65214501Srpaulo asn1_oid_to_str(&oid, obuf, sizeof(obuf)); 66214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf); 67214501Srpaulo params->alg = pkcs5_get_alg(&oid); 68214501Srpaulo if (params->alg == PKCS5_ALG_UNKNOWN) { 69214501Srpaulo wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption " 70214501Srpaulo "algorithm %s", obuf); 71214501Srpaulo return -1; 72214501Srpaulo } 73214501Srpaulo 74214501Srpaulo /* 75214501Srpaulo * PKCS#5, Section 8 76214501Srpaulo * PBEParameter ::= SEQUENCE { 77214501Srpaulo * salt OCTET STRING SIZE(8), 78214501Srpaulo * iterationCount INTEGER } 79214501Srpaulo */ 80214501Srpaulo 81214501Srpaulo if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || 82214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 83214501Srpaulo hdr.tag != ASN1_TAG_SEQUENCE) { 84214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE " 85214501Srpaulo "(PBEParameter) - found class %d tag 0x%x", 86214501Srpaulo hdr.class, hdr.tag); 87214501Srpaulo return -1; 88214501Srpaulo } 89214501Srpaulo pos = hdr.payload; 90214501Srpaulo end = hdr.payload + hdr.length; 91214501Srpaulo 92214501Srpaulo /* salt OCTET STRING SIZE(8) */ 93214501Srpaulo if (asn1_get_next(pos, end - pos, &hdr) < 0 || 94214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 95214501Srpaulo hdr.tag != ASN1_TAG_OCTETSTRING || 96214501Srpaulo hdr.length != 8) { 97214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) " 98214501Srpaulo "(salt) - found class %d tag 0x%x size %d", 99214501Srpaulo hdr.class, hdr.tag, hdr.length); 100214501Srpaulo return -1; 101214501Srpaulo } 102214501Srpaulo pos = hdr.payload + hdr.length; 103214501Srpaulo os_memcpy(params->salt, hdr.payload, hdr.length); 104214501Srpaulo params->salt_len = hdr.length; 105214501Srpaulo wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", 106214501Srpaulo params->salt, params->salt_len); 107214501Srpaulo 108214501Srpaulo /* iterationCount INTEGER */ 109214501Srpaulo if (asn1_get_next(pos, end - pos, &hdr) < 0 || 110214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { 111214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found " 112214501Srpaulo "class %d tag 0x%x", hdr.class, hdr.tag); 113214501Srpaulo return -1; 114214501Srpaulo } 115214501Srpaulo if (hdr.length == 1) 116214501Srpaulo params->iter_count = *hdr.payload; 117214501Srpaulo else if (hdr.length == 2) 118214501Srpaulo params->iter_count = WPA_GET_BE16(hdr.payload); 119214501Srpaulo else if (hdr.length == 4) 120214501Srpaulo params->iter_count = WPA_GET_BE32(hdr.payload); 121214501Srpaulo else { 122214501Srpaulo wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value " 123214501Srpaulo " (iterationCount)", 124214501Srpaulo hdr.payload, hdr.length); 125214501Srpaulo return -1; 126214501Srpaulo } 127214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", 128214501Srpaulo params->iter_count); 129214501Srpaulo if (params->iter_count == 0 || params->iter_count > 0xffff) { 130214501Srpaulo wpa_printf(MSG_INFO, "PKCS #5: Unsupported " 131214501Srpaulo "iterationCount=0x%x", params->iter_count); 132214501Srpaulo return -1; 133214501Srpaulo } 134214501Srpaulo 135214501Srpaulo return 0; 136214501Srpaulo} 137214501Srpaulo 138214501Srpaulo 139214501Srpaulostatic struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, 140214501Srpaulo const char *passwd) 141214501Srpaulo{ 142214501Srpaulo unsigned int i; 143214501Srpaulo u8 hash[MD5_MAC_LEN]; 144214501Srpaulo const u8 *addr[2]; 145214501Srpaulo size_t len[2]; 146214501Srpaulo 147214501Srpaulo if (params->alg != PKCS5_ALG_MD5_DES_CBC) 148214501Srpaulo return NULL; 149214501Srpaulo 150214501Srpaulo addr[0] = (const u8 *) passwd; 151214501Srpaulo len[0] = os_strlen(passwd); 152214501Srpaulo addr[1] = params->salt; 153214501Srpaulo len[1] = params->salt_len; 154214501Srpaulo if (md5_vector(2, addr, len, hash) < 0) 155214501Srpaulo return NULL; 156214501Srpaulo addr[0] = hash; 157214501Srpaulo len[0] = MD5_MAC_LEN; 158214501Srpaulo for (i = 1; i < params->iter_count; i++) { 159214501Srpaulo if (md5_vector(1, addr, len, hash) < 0) 160214501Srpaulo return NULL; 161214501Srpaulo } 162214501Srpaulo /* TODO: DES key parity bits(?) */ 163214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); 164214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); 165214501Srpaulo 166214501Srpaulo return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); 167214501Srpaulo} 168214501Srpaulo 169214501Srpaulo 170214501Srpaulou8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, 171214501Srpaulo const u8 *enc_data, size_t enc_data_len, 172214501Srpaulo const char *passwd, size_t *data_len) 173214501Srpaulo{ 174214501Srpaulo struct crypto_cipher *ctx; 175214501Srpaulo u8 *eb, pad; 176214501Srpaulo struct pkcs5_params params; 177214501Srpaulo unsigned int i; 178214501Srpaulo 179214501Srpaulo if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) { 180214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters"); 181214501Srpaulo return NULL; 182214501Srpaulo } 183214501Srpaulo 184214501Srpaulo ctx = pkcs5_crypto_init(¶ms, passwd); 185214501Srpaulo if (ctx == NULL) { 186214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto"); 187214501Srpaulo return NULL; 188214501Srpaulo } 189214501Srpaulo 190214501Srpaulo /* PKCS #5, Section 7 - Decryption process */ 191214501Srpaulo if (enc_data_len < 16 || enc_data_len % 8) { 192214501Srpaulo wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " 193214501Srpaulo "%d", (int) enc_data_len); 194214501Srpaulo crypto_cipher_deinit(ctx); 195214501Srpaulo return NULL; 196214501Srpaulo } 197214501Srpaulo 198214501Srpaulo eb = os_malloc(enc_data_len); 199214501Srpaulo if (eb == NULL) { 200214501Srpaulo crypto_cipher_deinit(ctx); 201214501Srpaulo return NULL; 202214501Srpaulo } 203214501Srpaulo 204214501Srpaulo if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { 205214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); 206214501Srpaulo crypto_cipher_deinit(ctx); 207214501Srpaulo os_free(eb); 208214501Srpaulo return NULL; 209214501Srpaulo } 210214501Srpaulo crypto_cipher_deinit(ctx); 211214501Srpaulo 212214501Srpaulo pad = eb[enc_data_len - 1]; 213214501Srpaulo if (pad > 8) { 214214501Srpaulo wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad); 215214501Srpaulo os_free(eb); 216214501Srpaulo return NULL; 217214501Srpaulo } 218214501Srpaulo for (i = enc_data_len - pad; i < enc_data_len; i++) { 219214501Srpaulo if (eb[i] != pad) { 220214501Srpaulo wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS", 221214501Srpaulo eb + enc_data_len - pad, pad); 222214501Srpaulo os_free(eb); 223214501Srpaulo return NULL; 224214501Srpaulo } 225214501Srpaulo } 226214501Srpaulo 227214501Srpaulo wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)", 228214501Srpaulo eb, enc_data_len - pad); 229214501Srpaulo 230214501Srpaulo *data_len = enc_data_len - pad; 231214501Srpaulo return eb; 232214501Srpaulo} 233