1214501Srpaulo/* 2214501Srpaulo * PKCS #5 (Password-based Encryption) 3337817Scy * Copyright (c) 2009-2015, 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" 14337817Scy#include "crypto/sha1.h" 15214501Srpaulo#include "asn1.h" 16214501Srpaulo#include "pkcs5.h" 17214501Srpaulo 18214501Srpaulo 19214501Srpaulostruct pkcs5_params { 20214501Srpaulo enum pkcs5_alg { 21214501Srpaulo PKCS5_ALG_UNKNOWN, 22337817Scy PKCS5_ALG_MD5_DES_CBC, 23337817Scy PKCS5_ALG_PBES2, 24337817Scy PKCS5_ALG_SHA1_3DES_CBC, 25214501Srpaulo } alg; 26337817Scy u8 salt[64]; 27214501Srpaulo size_t salt_len; 28214501Srpaulo unsigned int iter_count; 29337817Scy enum pbes2_enc_alg { 30337817Scy PBES2_ENC_ALG_UNKNOWN, 31337817Scy PBES2_ENC_ALG_DES_EDE3_CBC, 32337817Scy } enc_alg; 33337817Scy u8 iv[8]; 34337817Scy size_t iv_len; 35214501Srpaulo}; 36214501Srpaulo 37214501Srpaulo 38337817Scystatic int oid_is_rsadsi(struct asn1_oid *oid) 39337817Scy{ 40337817Scy return oid->len >= 4 && 41337817Scy oid->oid[0] == 1 /* iso */ && 42337817Scy oid->oid[1] == 2 /* member-body */ && 43337817Scy oid->oid[2] == 840 /* us */ && 44337817Scy oid->oid[3] == 113549 /* rsadsi */; 45337817Scy} 46337817Scy 47337817Scy 48337817Scystatic int pkcs5_is_oid(struct asn1_oid *oid, unsigned long alg) 49337817Scy{ 50337817Scy return oid->len == 7 && 51337817Scy oid_is_rsadsi(oid) && 52337817Scy oid->oid[4] == 1 /* pkcs */ && 53337817Scy oid->oid[5] == 5 /* pkcs-5 */ && 54337817Scy oid->oid[6] == alg; 55337817Scy} 56337817Scy 57337817Scy 58337817Scystatic int enc_alg_is_oid(struct asn1_oid *oid, unsigned long alg) 59337817Scy{ 60337817Scy return oid->len == 6 && 61337817Scy oid_is_rsadsi(oid) && 62337817Scy oid->oid[4] == 3 /* encryptionAlgorithm */ && 63337817Scy oid->oid[5] == alg; 64337817Scy} 65337817Scy 66337817Scy 67337817Scystatic int pkcs12_is_pbe_oid(struct asn1_oid *oid, unsigned long alg) 68337817Scy{ 69337817Scy return oid->len == 8 && 70337817Scy oid_is_rsadsi(oid) && 71337817Scy oid->oid[4] == 1 /* pkcs */ && 72337817Scy oid->oid[5] == 12 /* pkcs-12 */ && 73337817Scy oid->oid[6] == 1 /* pkcs-12PbeIds */ && 74337817Scy oid->oid[7] == alg; 75337817Scy} 76337817Scy 77337817Scy 78252726Srpaulostatic enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) 79214501Srpaulo{ 80337817Scy if (pkcs5_is_oid(oid, 3)) /* pbeWithMD5AndDES-CBC (PBES1) */ 81214501Srpaulo return PKCS5_ALG_MD5_DES_CBC; 82337817Scy if (pkcs12_is_pbe_oid(oid, 3)) /* pbeWithSHAAnd3-KeyTripleDES-CBC */ 83337817Scy return PKCS5_ALG_SHA1_3DES_CBC; 84337817Scy if (pkcs5_is_oid(oid, 13)) /* id-PBES2 (PBES2) */ 85337817Scy return PKCS5_ALG_PBES2; 86214501Srpaulo return PKCS5_ALG_UNKNOWN; 87214501Srpaulo} 88214501Srpaulo 89214501Srpaulo 90337817Scystatic int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos, 91337817Scy const u8 *enc_alg_end) 92337817Scy{ 93337817Scy struct asn1_hdr hdr; 94337817Scy const u8 *end, *kdf_end; 95337817Scy struct asn1_oid oid; 96337817Scy char obuf[80]; 97337817Scy 98337817Scy /* 99337817Scy * RFC 2898, Ch. A.4 100337817Scy * 101337817Scy * PBES2-params ::= SEQUENCE { 102337817Scy * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, 103337817Scy * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } 104337817Scy * 105337817Scy * PBES2-KDFs ALGORITHM-IDENTIFIER ::= 106337817Scy * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } 107337817Scy */ 108337817Scy 109337817Scy if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || 110337817Scy hdr.class != ASN1_CLASS_UNIVERSAL || 111337817Scy hdr.tag != ASN1_TAG_SEQUENCE) { 112337817Scy wpa_printf(MSG_DEBUG, 113337817Scy "PKCS #5: Expected SEQUENCE (PBES2-params) - found class %d tag 0x%x", 114337817Scy hdr.class, hdr.tag); 115337817Scy return -1; 116337817Scy } 117337817Scy pos = hdr.payload; 118337817Scy end = hdr.payload + hdr.length; 119337817Scy 120337817Scy if (asn1_get_next(pos, end - pos, &hdr) < 0 || 121337817Scy hdr.class != ASN1_CLASS_UNIVERSAL || 122337817Scy hdr.tag != ASN1_TAG_SEQUENCE) { 123337817Scy wpa_printf(MSG_DEBUG, 124337817Scy "PKCS #5: Expected SEQUENCE (keyDerivationFunc) - found class %d tag 0x%x", 125337817Scy hdr.class, hdr.tag); 126337817Scy return -1; 127337817Scy } 128337817Scy 129337817Scy pos = hdr.payload; 130337817Scy kdf_end = end = hdr.payload + hdr.length; 131337817Scy 132337817Scy if (asn1_get_oid(pos, end - pos, &oid, &pos)) { 133337817Scy wpa_printf(MSG_DEBUG, 134337817Scy "PKCS #5: Failed to parse OID (keyDerivationFunc algorithm)"); 135337817Scy return -1; 136337817Scy } 137337817Scy 138337817Scy asn1_oid_to_str(&oid, obuf, sizeof(obuf)); 139337817Scy wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 keyDerivationFunc algorithm %s", 140337817Scy obuf); 141337817Scy if (!pkcs5_is_oid(&oid, 12)) /* id-PBKDF2 */ { 142337817Scy wpa_printf(MSG_DEBUG, 143337817Scy "PKCS #5: Unsupported PBES2 keyDerivationFunc algorithm %s", 144337817Scy obuf); 145337817Scy return -1; 146337817Scy } 147337817Scy 148337817Scy /* 149337817Scy * RFC 2898, C. 150337817Scy * 151337817Scy * PBKDF2-params ::= SEQUENCE { 152337817Scy * salt CHOICE { 153337817Scy * specified OCTET STRING, 154337817Scy * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} 155337817Scy * }, 156337817Scy * iterationCount INTEGER (1..MAX), 157337817Scy * keyLength INTEGER (1..MAX) OPTIONAL, 158337817Scy * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT 159337817Scy * algid-hmacWithSHA1 160337817Scy * } 161337817Scy */ 162337817Scy 163337817Scy if (asn1_get_next(pos, end - pos, &hdr) < 0 || 164337817Scy hdr.class != ASN1_CLASS_UNIVERSAL || 165337817Scy hdr.tag != ASN1_TAG_SEQUENCE) { 166337817Scy wpa_printf(MSG_DEBUG, 167337817Scy "PKCS #5: Expected SEQUENCE (PBKDF2-params) - found class %d tag 0x%x", 168337817Scy hdr.class, hdr.tag); 169337817Scy return -1; 170337817Scy } 171337817Scy 172337817Scy pos = hdr.payload; 173337817Scy end = hdr.payload + hdr.length; 174337817Scy 175337817Scy /* For now, only support the salt CHOICE specified (OCTET STRING) */ 176337817Scy if (asn1_get_next(pos, end - pos, &hdr) < 0 || 177337817Scy hdr.class != ASN1_CLASS_UNIVERSAL || 178337817Scy hdr.tag != ASN1_TAG_OCTETSTRING || 179337817Scy hdr.length > sizeof(params->salt)) { 180337817Scy wpa_printf(MSG_DEBUG, 181337817Scy "PKCS #5: Expected OCTET STRING (salt.specified) - found class %d tag 0x%x size %d", 182337817Scy hdr.class, hdr.tag, hdr.length); 183337817Scy return -1; 184337817Scy } 185337817Scy pos = hdr.payload + hdr.length; 186337817Scy os_memcpy(params->salt, hdr.payload, hdr.length); 187337817Scy params->salt_len = hdr.length; 188337817Scy wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", params->salt, params->salt_len); 189337817Scy 190337817Scy /* iterationCount INTEGER */ 191337817Scy if (asn1_get_next(pos, end - pos, &hdr) < 0 || 192337817Scy hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { 193337817Scy wpa_printf(MSG_DEBUG, 194337817Scy "PKCS #5: Expected INTEGER - found class %d tag 0x%x", 195337817Scy hdr.class, hdr.tag); 196337817Scy return -1; 197337817Scy } 198337817Scy if (hdr.length == 1) { 199337817Scy params->iter_count = *hdr.payload; 200337817Scy } else if (hdr.length == 2) { 201337817Scy params->iter_count = WPA_GET_BE16(hdr.payload); 202337817Scy } else if (hdr.length == 4) { 203337817Scy params->iter_count = WPA_GET_BE32(hdr.payload); 204337817Scy } else { 205337817Scy wpa_hexdump(MSG_DEBUG, 206337817Scy "PKCS #5: Unsupported INTEGER value (iterationCount)", 207337817Scy hdr.payload, hdr.length); 208337817Scy return -1; 209337817Scy } 210337817Scy wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", 211337817Scy params->iter_count); 212337817Scy if (params->iter_count == 0 || params->iter_count > 0xffff) { 213337817Scy wpa_printf(MSG_INFO, "PKCS #5: Unsupported iterationCount=0x%x", 214337817Scy params->iter_count); 215337817Scy return -1; 216337817Scy } 217337817Scy 218337817Scy /* For now, ignore optional keyLength and prf */ 219337817Scy 220337817Scy pos = kdf_end; 221337817Scy 222337817Scy /* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} */ 223337817Scy 224337817Scy if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || 225337817Scy hdr.class != ASN1_CLASS_UNIVERSAL || 226337817Scy hdr.tag != ASN1_TAG_SEQUENCE) { 227337817Scy wpa_printf(MSG_DEBUG, 228337817Scy "PKCS #5: Expected SEQUENCE (encryptionScheme) - found class %d tag 0x%x", 229337817Scy hdr.class, hdr.tag); 230337817Scy return -1; 231337817Scy } 232337817Scy 233337817Scy pos = hdr.payload; 234337817Scy end = hdr.payload + hdr.length; 235337817Scy 236337817Scy if (asn1_get_oid(pos, end - pos, &oid, &pos)) { 237337817Scy wpa_printf(MSG_DEBUG, 238337817Scy "PKCS #5: Failed to parse OID (encryptionScheme algorithm)"); 239337817Scy return -1; 240337817Scy } 241337817Scy 242337817Scy asn1_oid_to_str(&oid, obuf, sizeof(obuf)); 243337817Scy wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 encryptionScheme algorithm %s", 244337817Scy obuf); 245337817Scy if (enc_alg_is_oid(&oid, 7)) { 246337817Scy params->enc_alg = PBES2_ENC_ALG_DES_EDE3_CBC; 247337817Scy } else { 248337817Scy wpa_printf(MSG_DEBUG, 249337817Scy "PKCS #5: Unsupported PBES2 encryptionScheme algorithm %s", 250337817Scy obuf); 251337817Scy return -1; 252337817Scy } 253337817Scy 254337817Scy /* 255337817Scy * RFC 2898, B.2.2: 256337817Scy * The parameters field associated with this OID in an 257337817Scy * AlgorithmIdentifier shall have type OCTET STRING (SIZE(8)), 258337817Scy * specifying the initialization vector for CBC mode. 259337817Scy */ 260337817Scy if (asn1_get_next(pos, end - pos, &hdr) < 0 || 261337817Scy hdr.class != ASN1_CLASS_UNIVERSAL || 262337817Scy hdr.tag != ASN1_TAG_OCTETSTRING || 263337817Scy hdr.length != 8) { 264337817Scy wpa_printf(MSG_DEBUG, 265337817Scy "PKCS #5: Expected OCTET STRING (SIZE(8)) (IV) - found class %d tag 0x%x size %d", 266337817Scy hdr.class, hdr.tag, hdr.length); 267337817Scy return -1; 268337817Scy } 269337817Scy os_memcpy(params->iv, hdr.payload, hdr.length); 270337817Scy params->iv_len = hdr.length; 271337817Scy wpa_hexdump(MSG_DEBUG, "PKCS #5: IV", params->iv, params->iv_len); 272337817Scy 273337817Scy return 0; 274337817Scy} 275337817Scy 276337817Scy 277214501Srpaulostatic int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len, 278214501Srpaulo struct pkcs5_params *params) 279214501Srpaulo{ 280214501Srpaulo struct asn1_hdr hdr; 281214501Srpaulo const u8 *enc_alg_end, *pos, *end; 282214501Srpaulo struct asn1_oid oid; 283214501Srpaulo char obuf[80]; 284214501Srpaulo 285214501Srpaulo /* AlgorithmIdentifier */ 286214501Srpaulo 287214501Srpaulo enc_alg_end = enc_alg + enc_alg_len; 288214501Srpaulo 289214501Srpaulo os_memset(params, 0, sizeof(*params)); 290214501Srpaulo 291214501Srpaulo if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) { 292214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID " 293214501Srpaulo "(algorithm)"); 294214501Srpaulo return -1; 295214501Srpaulo } 296214501Srpaulo 297214501Srpaulo asn1_oid_to_str(&oid, obuf, sizeof(obuf)); 298214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf); 299214501Srpaulo params->alg = pkcs5_get_alg(&oid); 300214501Srpaulo if (params->alg == PKCS5_ALG_UNKNOWN) { 301214501Srpaulo wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption " 302214501Srpaulo "algorithm %s", obuf); 303214501Srpaulo return -1; 304214501Srpaulo } 305214501Srpaulo 306337817Scy if (params->alg == PKCS5_ALG_PBES2) 307337817Scy return pkcs5_get_params_pbes2(params, pos, enc_alg_end); 308337817Scy 309337817Scy /* PBES1 */ 310337817Scy 311214501Srpaulo /* 312214501Srpaulo * PKCS#5, Section 8 313214501Srpaulo * PBEParameter ::= SEQUENCE { 314214501Srpaulo * salt OCTET STRING SIZE(8), 315214501Srpaulo * iterationCount INTEGER } 316337817Scy * 317337817Scy * Note: The same implementation can be used to parse the PKCS #12 318337817Scy * version described in RFC 7292, C: 319337817Scy * pkcs-12PbeParams ::= SEQUENCE { 320337817Scy * salt OCTET STRING, 321337817Scy * iterations INTEGER 322337817Scy * } 323214501Srpaulo */ 324214501Srpaulo 325214501Srpaulo if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || 326214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 327214501Srpaulo hdr.tag != ASN1_TAG_SEQUENCE) { 328214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE " 329214501Srpaulo "(PBEParameter) - found class %d tag 0x%x", 330214501Srpaulo hdr.class, hdr.tag); 331214501Srpaulo return -1; 332214501Srpaulo } 333214501Srpaulo pos = hdr.payload; 334214501Srpaulo end = hdr.payload + hdr.length; 335214501Srpaulo 336337817Scy /* salt OCTET STRING SIZE(8) (PKCS #5) or OCTET STRING (PKCS #12) */ 337214501Srpaulo if (asn1_get_next(pos, end - pos, &hdr) < 0 || 338214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 339214501Srpaulo hdr.tag != ASN1_TAG_OCTETSTRING || 340337817Scy hdr.length > sizeof(params->salt)) { 341214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) " 342214501Srpaulo "(salt) - found class %d tag 0x%x size %d", 343214501Srpaulo hdr.class, hdr.tag, hdr.length); 344214501Srpaulo return -1; 345214501Srpaulo } 346214501Srpaulo pos = hdr.payload + hdr.length; 347214501Srpaulo os_memcpy(params->salt, hdr.payload, hdr.length); 348214501Srpaulo params->salt_len = hdr.length; 349214501Srpaulo wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", 350214501Srpaulo params->salt, params->salt_len); 351214501Srpaulo 352214501Srpaulo /* iterationCount INTEGER */ 353214501Srpaulo if (asn1_get_next(pos, end - pos, &hdr) < 0 || 354214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { 355214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found " 356214501Srpaulo "class %d tag 0x%x", hdr.class, hdr.tag); 357214501Srpaulo return -1; 358214501Srpaulo } 359214501Srpaulo if (hdr.length == 1) 360214501Srpaulo params->iter_count = *hdr.payload; 361214501Srpaulo else if (hdr.length == 2) 362214501Srpaulo params->iter_count = WPA_GET_BE16(hdr.payload); 363214501Srpaulo else if (hdr.length == 4) 364214501Srpaulo params->iter_count = WPA_GET_BE32(hdr.payload); 365214501Srpaulo else { 366214501Srpaulo wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value " 367214501Srpaulo " (iterationCount)", 368214501Srpaulo hdr.payload, hdr.length); 369214501Srpaulo return -1; 370214501Srpaulo } 371214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", 372214501Srpaulo params->iter_count); 373214501Srpaulo if (params->iter_count == 0 || params->iter_count > 0xffff) { 374214501Srpaulo wpa_printf(MSG_INFO, "PKCS #5: Unsupported " 375214501Srpaulo "iterationCount=0x%x", params->iter_count); 376214501Srpaulo return -1; 377214501Srpaulo } 378214501Srpaulo 379214501Srpaulo return 0; 380214501Srpaulo} 381214501Srpaulo 382214501Srpaulo 383337817Scystatic struct crypto_cipher * 384337817Scypkcs5_crypto_init_pbes2(struct pkcs5_params *params, const char *passwd) 385337817Scy{ 386337817Scy u8 key[24]; 387337817Scy 388337817Scy if (params->enc_alg != PBES2_ENC_ALG_DES_EDE3_CBC || 389337817Scy params->iv_len != 8) 390337817Scy return NULL; 391337817Scy 392337817Scy wpa_hexdump_ascii_key(MSG_DEBUG, "PKCS #5: PBES2 password for PBKDF2", 393337817Scy passwd, os_strlen(passwd)); 394337817Scy wpa_hexdump(MSG_DEBUG, "PKCS #5: PBES2 salt for PBKDF2", 395337817Scy params->salt, params->salt_len); 396337817Scy wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 PBKDF2 iterations: %u", 397337817Scy params->iter_count); 398337817Scy if (pbkdf2_sha1(passwd, params->salt, params->salt_len, 399337817Scy params->iter_count, key, sizeof(key)) < 0) 400337817Scy return NULL; 401337817Scy wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES EDE3 key", key, sizeof(key)); 402337817Scy wpa_hexdump(MSG_DEBUG, "PKCS #5: DES IV", params->iv, params->iv_len); 403337817Scy 404337817Scy return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, params->iv, 405337817Scy key, sizeof(key)); 406337817Scy} 407337817Scy 408337817Scy 409337817Scystatic void add_byte_array_mod(u8 *a, const u8 *b, size_t len) 410337817Scy{ 411337817Scy size_t i; 412337817Scy unsigned int carry = 0; 413337817Scy 414337817Scy for (i = len - 1; i < len; i--) { 415337817Scy carry = carry + a[i] + b[i]; 416337817Scy a[i] = carry & 0xff; 417337817Scy carry >>= 8; 418337817Scy } 419337817Scy} 420337817Scy 421337817Scy 422337817Scystatic int pkcs12_key_gen(const u8 *pw, size_t pw_len, const u8 *salt, 423337817Scy size_t salt_len, u8 id, unsigned int iter, 424337817Scy size_t out_len, u8 *out) 425337817Scy{ 426337817Scy unsigned int u, v, S_len, P_len, i; 427337817Scy u8 *D = NULL, *I = NULL, *B = NULL, *pos; 428337817Scy int res = -1; 429337817Scy 430337817Scy /* RFC 7292, B.2 */ 431337817Scy u = SHA1_MAC_LEN; 432337817Scy v = 64; 433337817Scy 434337817Scy /* D = copies of ID */ 435337817Scy D = os_malloc(v); 436337817Scy if (!D) 437337817Scy goto done; 438337817Scy os_memset(D, id, v); 439337817Scy 440337817Scy /* S = copies of salt; P = copies of password, I = S || P */ 441337817Scy S_len = v * ((salt_len + v - 1) / v); 442337817Scy P_len = v * ((pw_len + v - 1) / v); 443337817Scy I = os_malloc(S_len + P_len); 444337817Scy if (!I) 445337817Scy goto done; 446337817Scy pos = I; 447337817Scy if (salt_len) { 448337817Scy for (i = 0; i < S_len; i++) 449337817Scy *pos++ = salt[i % salt_len]; 450337817Scy } 451337817Scy if (pw_len) { 452337817Scy for (i = 0; i < P_len; i++) 453337817Scy *pos++ = pw[i % pw_len]; 454337817Scy } 455337817Scy 456337817Scy B = os_malloc(v); 457337817Scy if (!B) 458337817Scy goto done; 459337817Scy 460337817Scy for (;;) { 461337817Scy u8 hash[SHA1_MAC_LEN]; 462337817Scy const u8 *addr[2]; 463337817Scy size_t len[2]; 464337817Scy 465337817Scy addr[0] = D; 466337817Scy len[0] = v; 467337817Scy addr[1] = I; 468337817Scy len[1] = S_len + P_len; 469337817Scy if (sha1_vector(2, addr, len, hash) < 0) 470337817Scy goto done; 471337817Scy 472337817Scy addr[0] = hash; 473337817Scy len[0] = SHA1_MAC_LEN; 474337817Scy for (i = 1; i < iter; i++) { 475337817Scy if (sha1_vector(1, addr, len, hash) < 0) 476337817Scy goto done; 477337817Scy } 478337817Scy 479337817Scy if (out_len <= u) { 480337817Scy os_memcpy(out, hash, out_len); 481337817Scy res = 0; 482337817Scy goto done; 483337817Scy } 484337817Scy 485337817Scy os_memcpy(out, hash, u); 486337817Scy out += u; 487337817Scy out_len -= u; 488337817Scy 489337817Scy /* I_j = (I_j + B + 1) mod 2^(v*8) */ 490337817Scy /* B = copies of Ai (final hash value) */ 491337817Scy for (i = 0; i < v; i++) 492337817Scy B[i] = hash[i % u]; 493337817Scy inc_byte_array(B, v); 494337817Scy for (i = 0; i < S_len + P_len; i += v) 495337817Scy add_byte_array_mod(&I[i], B, v); 496337817Scy } 497337817Scy 498337817Scydone: 499337817Scy os_free(B); 500337817Scy os_free(I); 501337817Scy os_free(D); 502337817Scy return res; 503337817Scy} 504337817Scy 505337817Scy 506337817Scy#define PKCS12_ID_ENC 1 507337817Scy#define PKCS12_ID_IV 2 508337817Scy#define PKCS12_ID_MAC 3 509337817Scy 510337817Scystatic struct crypto_cipher * 511337817Scypkcs12_crypto_init_sha1(struct pkcs5_params *params, const char *passwd) 512337817Scy{ 513337817Scy unsigned int i; 514337817Scy u8 *pw; 515337817Scy size_t pw_len; 516337817Scy u8 key[24]; 517337817Scy u8 iv[8]; 518337817Scy 519337817Scy if (params->alg != PKCS5_ALG_SHA1_3DES_CBC) 520337817Scy return NULL; 521337817Scy 522337817Scy pw_len = passwd ? os_strlen(passwd) : 0; 523337817Scy pw = os_malloc(2 * (pw_len + 1)); 524337817Scy if (!pw) 525337817Scy return NULL; 526337817Scy if (pw_len) { 527337817Scy for (i = 0; i <= pw_len; i++) 528337817Scy WPA_PUT_BE16(&pw[2 * i], passwd[i]); 529337817Scy pw_len = 2 * (pw_len + 1); 530337817Scy } 531337817Scy 532337817Scy if (pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len, 533337817Scy PKCS12_ID_ENC, params->iter_count, 534337817Scy sizeof(key), key) < 0 || 535337817Scy pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len, 536337817Scy PKCS12_ID_IV, params->iter_count, 537337817Scy sizeof(iv), iv) < 0) { 538337817Scy os_free(pw); 539337817Scy return NULL; 540337817Scy } 541337817Scy 542337817Scy os_free(pw); 543337817Scy 544337817Scy wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES key", key, sizeof(key)); 545337817Scy wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES IV", iv, sizeof(iv)); 546337817Scy 547337817Scy return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, iv, key, sizeof(key)); 548337817Scy} 549337817Scy 550337817Scy 551214501Srpaulostatic struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, 552214501Srpaulo const char *passwd) 553214501Srpaulo{ 554214501Srpaulo unsigned int i; 555214501Srpaulo u8 hash[MD5_MAC_LEN]; 556214501Srpaulo const u8 *addr[2]; 557214501Srpaulo size_t len[2]; 558214501Srpaulo 559337817Scy if (params->alg == PKCS5_ALG_PBES2) 560337817Scy return pkcs5_crypto_init_pbes2(params, passwd); 561337817Scy 562337817Scy if (params->alg == PKCS5_ALG_SHA1_3DES_CBC) 563337817Scy return pkcs12_crypto_init_sha1(params, passwd); 564337817Scy 565214501Srpaulo if (params->alg != PKCS5_ALG_MD5_DES_CBC) 566214501Srpaulo return NULL; 567214501Srpaulo 568214501Srpaulo addr[0] = (const u8 *) passwd; 569214501Srpaulo len[0] = os_strlen(passwd); 570214501Srpaulo addr[1] = params->salt; 571214501Srpaulo len[1] = params->salt_len; 572214501Srpaulo if (md5_vector(2, addr, len, hash) < 0) 573214501Srpaulo return NULL; 574214501Srpaulo addr[0] = hash; 575214501Srpaulo len[0] = MD5_MAC_LEN; 576214501Srpaulo for (i = 1; i < params->iter_count; i++) { 577214501Srpaulo if (md5_vector(1, addr, len, hash) < 0) 578214501Srpaulo return NULL; 579214501Srpaulo } 580214501Srpaulo /* TODO: DES key parity bits(?) */ 581214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); 582214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); 583214501Srpaulo 584214501Srpaulo return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); 585214501Srpaulo} 586214501Srpaulo 587214501Srpaulo 588214501Srpaulou8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, 589214501Srpaulo const u8 *enc_data, size_t enc_data_len, 590214501Srpaulo const char *passwd, size_t *data_len) 591214501Srpaulo{ 592214501Srpaulo struct crypto_cipher *ctx; 593214501Srpaulo u8 *eb, pad; 594214501Srpaulo struct pkcs5_params params; 595214501Srpaulo unsigned int i; 596214501Srpaulo 597214501Srpaulo if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) { 598214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters"); 599214501Srpaulo return NULL; 600214501Srpaulo } 601214501Srpaulo 602214501Srpaulo ctx = pkcs5_crypto_init(¶ms, passwd); 603214501Srpaulo if (ctx == NULL) { 604214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto"); 605214501Srpaulo return NULL; 606214501Srpaulo } 607214501Srpaulo 608214501Srpaulo /* PKCS #5, Section 7 - Decryption process */ 609214501Srpaulo if (enc_data_len < 16 || enc_data_len % 8) { 610214501Srpaulo wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " 611214501Srpaulo "%d", (int) enc_data_len); 612214501Srpaulo crypto_cipher_deinit(ctx); 613214501Srpaulo return NULL; 614214501Srpaulo } 615214501Srpaulo 616214501Srpaulo eb = os_malloc(enc_data_len); 617214501Srpaulo if (eb == NULL) { 618214501Srpaulo crypto_cipher_deinit(ctx); 619214501Srpaulo return NULL; 620214501Srpaulo } 621214501Srpaulo 622214501Srpaulo if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { 623214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); 624214501Srpaulo crypto_cipher_deinit(ctx); 625214501Srpaulo os_free(eb); 626214501Srpaulo return NULL; 627214501Srpaulo } 628214501Srpaulo crypto_cipher_deinit(ctx); 629214501Srpaulo 630214501Srpaulo pad = eb[enc_data_len - 1]; 631214501Srpaulo if (pad > 8) { 632214501Srpaulo wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad); 633214501Srpaulo os_free(eb); 634214501Srpaulo return NULL; 635214501Srpaulo } 636214501Srpaulo for (i = enc_data_len - pad; i < enc_data_len; i++) { 637214501Srpaulo if (eb[i] != pad) { 638214501Srpaulo wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS", 639214501Srpaulo eb + enc_data_len - pad, pad); 640214501Srpaulo os_free(eb); 641214501Srpaulo return NULL; 642214501Srpaulo } 643214501Srpaulo } 644214501Srpaulo 645214501Srpaulo wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)", 646214501Srpaulo eb, enc_data_len - pad); 647214501Srpaulo 648214501Srpaulo *data_len = enc_data_len - pad; 649214501Srpaulo return eb; 650214501Srpaulo} 651