pkcs5.c revision 214501
1139823Simp/* 254263Sshin * PKCS #5 (Password-based Encryption) 354263Sshin * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 454263Sshin * 554263Sshin * This program is free software; you can redistribute it and/or modify 654263Sshin * it under the terms of the GNU General Public License version 2 as 754263Sshin * published by the Free Software Foundation. 854263Sshin * 954263Sshin * Alternatively, this software may be distributed under the terms of BSD 1054263Sshin * license. 1154263Sshin * 1254263Sshin * See README and COPYING for more details. 1354263Sshin */ 1454263Sshin 1554263Sshin#include "includes.h" 1654263Sshin 1754263Sshin#include "common.h" 1854263Sshin#include "crypto/crypto.h" 1954263Sshin#include "crypto/md5.h" 2054263Sshin#include "asn1.h" 2154263Sshin#include "pkcs5.h" 2254263Sshin 2354263Sshin 2454263Sshinstruct pkcs5_params { 2554263Sshin enum pkcs5_alg { 2654263Sshin PKCS5_ALG_UNKNOWN, 2754263Sshin PKCS5_ALG_MD5_DES_CBC 28273087Sae } alg; 29273087Sae u8 salt[8]; 3054263Sshin size_t salt_len; 3154263Sshin unsigned int iter_count; 32172467Ssilby}; 33172467Ssilby 34172467Ssilby 3562587Sitojunenum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) 3654263Sshin{ 3754263Sshin if (oid->len == 7 && 3854263Sshin oid->oid[0] == 1 /* iso */ && 39273087Sae oid->oid[1] == 2 /* member-body */ && 40273087Sae oid->oid[2] == 840 /* us */ && 4154263Sshin oid->oid[3] == 113549 /* rsadsi */ && 4254263Sshin oid->oid[4] == 1 /* pkcs */ && 4354263Sshin oid->oid[5] == 5 /* pkcs-5 */ && 4454263Sshin oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */) 4554263Sshin return PKCS5_ALG_MD5_DES_CBC; 4654263Sshin 4754263Sshin return PKCS5_ALG_UNKNOWN; 48105293Sume} 4962587Sitojun 5062587Sitojun 5154263Sshinstatic int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len, 52257176Sglebius struct pkcs5_params *params) 5354263Sshin{ 54196019Srwatson struct asn1_hdr hdr; 5554263Sshin const u8 *enc_alg_end, *pos, *end; 5654263Sshin struct asn1_oid oid; 5754263Sshin char obuf[80]; 5854263Sshin 5954263Sshin /* AlgorithmIdentifier */ 6062587Sitojun 6162587Sitojun enc_alg_end = enc_alg + enc_alg_len; 6255009Sshin 6362587Sitojun os_memset(params, 0, sizeof(*params)); 6454263Sshin 6562587Sitojun if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) { 6654263Sshin wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID " 6754263Sshin "(algorithm)"); 68273087Sae return -1; 6954263Sshin } 70105293Sume 71105293Sume asn1_oid_to_str(&oid, obuf, sizeof(obuf)); 72276148Sae wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf); 73105293Sume params->alg = pkcs5_get_alg(&oid); 74105293Sume if (params->alg == PKCS5_ALG_UNKNOWN) { 75276148Sae wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption " 76152242Sru "algorithm %s", obuf); 77152242Sru return -1; 78152242Sru } 79152242Sru 80152242Sru /* 81270008Skevlo * PKCS#5, Section 8 82152242Sru * PBEParameter ::= SEQUENCE { 83152242Sru * salt OCTET STRING SIZE(8), 84105293Sume * iterationCount INTEGER } 85105293Sume */ 86276148Sae 87276148Sae if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || 88207369Sbz hdr.class != ASN1_CLASS_UNIVERSAL || 89274225Sglebius hdr.tag != ASN1_TAG_SEQUENCE) { 90195699Srwatson wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE " 9154263Sshin "(PBEParameter) - found class %d tag 0x%x", 9254263Sshin hdr.class, hdr.tag); 93273087Sae return -1; 9454263Sshin } 95273087Sae pos = hdr.payload; 96147256Sbrooks end = hdr.payload + hdr.length; 97273087Sae 98273087Sae /* salt OCTET STRING SIZE(8) */ 9954263Sshin if (asn1_get_next(pos, end - pos, &hdr) < 0 || 10054263Sshin hdr.class != ASN1_CLASS_UNIVERSAL || 101189494Smarius hdr.tag != ASN1_TAG_OCTETSTRING || 102189494Smarius hdr.length != 8) { 103273087Sae wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) " 104189494Smarius "(salt) - found class %d tag 0x%x size %d", 105189494Smarius hdr.class, hdr.tag, hdr.length); 106243882Sglebius return -1; 107273087Sae } 108273087Sae pos = hdr.payload + hdr.length; 109189494Smarius os_memcpy(params->salt, hdr.payload, hdr.length); 110273087Sae params->salt_len = hdr.length; 111189494Smarius wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", 112189494Smarius params->salt, params->salt_len); 113189494Smarius 114189494Smarius /* iterationCount INTEGER */ 115189494Smarius if (asn1_get_next(pos, end - pos, &hdr) < 0 || 116189494Smarius hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { 117189494Smarius wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found " 118273087Sae "class %d tag 0x%x", hdr.class, hdr.tag); 119273087Sae return -1; 120273087Sae } 121273087Sae if (hdr.length == 1) 122273087Sae params->iter_count = *hdr.payload; 123273087Sae else if (hdr.length == 2) 12454263Sshin params->iter_count = WPA_GET_BE16(hdr.payload); 125273087Sae else if (hdr.length == 4) 126273087Sae params->iter_count = WPA_GET_BE32(hdr.payload); 12754263Sshin else { 128273087Sae wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value " 129273087Sae " (iterationCount)", 130273087Sae hdr.payload, hdr.length); 131273087Sae return -1; 132273087Sae } 13362587Sitojun wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", 134273087Sae params->iter_count); 13554263Sshin if (params->iter_count == 0 || params->iter_count > 0xffff) { 13654263Sshin wpa_printf(MSG_INFO, "PKCS #5: Unsupported " 137276148Sae "iterationCount=0x%x", params->iter_count); 138269699Skevlo return -1; 13954263Sshin } 140273087Sae 141147503Sbz return 0; 142273087Sae} 14354263Sshin 144273087Sae 14554263Sshinstatic struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, 146273087Sae const char *passwd) 147147503Sbz{ 148147503Sbz unsigned int i; 149196039Srwatson u8 hash[MD5_MAC_LEN]; 150269699Skevlo const u8 *addr[2]; 151147503Sbz size_t len[2]; 152147503Sbz 153273087Sae if (params->alg != PKCS5_ALG_MD5_DES_CBC) 154273087Sae return NULL; 155273087Sae 156273087Sae addr[0] = (const u8 *) passwd; 157273087Sae len[0] = os_strlen(passwd); 158273087Sae addr[1] = params->salt; 15954263Sshin len[1] = params->salt_len; 160196039Srwatson if (md5_vector(2, addr, len, hash) < 0) 16154263Sshin return NULL; 162269699Skevlo addr[0] = hash; 16354263Sshin len[0] = MD5_MAC_LEN; 16462587Sitojun for (i = 1; i < params->iter_count; i++) { 16562587Sitojun if (md5_vector(1, addr, len, hash) < 0) 166105293Sume return NULL; 16762587Sitojun } 168105293Sume /* TODO: DES key parity bits(?) */ 169169454Srwatson wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); 17062587Sitojun wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); 171282965Sae 17262587Sitojun return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); 173273087Sae} 17462587Sitojun 17562587Sitojun 176282965Saeu8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, 177273087Sae const u8 *enc_data, size_t enc_data_len, 178282965Sae const char *passwd, size_t *data_len) 179282965Sae{ 180282965Sae struct crypto_cipher *ctx; 181282965Sae u8 *eb, pad; 182282965Sae struct pkcs5_params params; 183282965Sae unsigned int i; 18462587Sitojun 18562587Sitojun if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) { 186105293Sume wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters"); 187273087Sae return NULL; 188105293Sume } 189273087Sae 190273087Sae ctx = pkcs5_crypto_init(¶ms, passwd); 191273087Sae if (ctx == NULL) { 192273087Sae wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto"); 19362587Sitojun return NULL; 194194951Srwatson } 19562587Sitojun 196147256Sbrooks /* PKCS #5, Section 7 - Decryption process */ 19762587Sitojun if (enc_data_len < 16 || enc_data_len % 8) { 19862587Sitojun wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " 19962587Sitojun "%d", (int) enc_data_len); 20062587Sitojun crypto_cipher_deinit(ctx); 20162587Sitojun return NULL; 20262587Sitojun } 203105293Sume 204178888Sjulian eb = os_malloc(enc_data_len); 205178888Sjulian if (eb == NULL) { 206178888Sjulian crypto_cipher_deinit(ctx); 207105293Sume return NULL; 20878064Sume } 209172307Scsjp 210273087Sae if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { 21162587Sitojun wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); 212172307Scsjp crypto_cipher_deinit(ctx); 21362587Sitojun os_free(eb); 214282965Sae return NULL; 21562587Sitojun } 216105293Sume crypto_cipher_deinit(ctx); 217105293Sume 218105293Sume pad = eb[enc_data_len - 1]; 219105293Sume if (pad > 8) { 220105293Sume wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad); 221105293Sume os_free(eb); 222273087Sae return NULL; 223105293Sume } 224105293Sume for (i = enc_data_len - pad; i < enc_data_len; i++) { 225105293Sume if (eb[i] != pad) { 226105293Sume wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS", 227105293Sume eb + enc_data_len - pad, pad); 228105293Sume os_free(eb); 229105293Sume return NULL; 230273087Sae } 231105293Sume } 232105293Sume 233105293Sume wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)", 234273087Sae eb, enc_data_len - pad); 235105293Sume 236105293Sume *data_len = enc_data_len - pad; 237105293Sume return eb; 238169454Srwatson} 239105293Sume