Return to pkcs12.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / credentials / containers |
1.1 misho 1: /* 2: * Copyright (C) 2013 Tobias Brunner 3: * HSR Hochschule fuer Technik Rapperswil 4: * 5: * This program is free software; you can redistribute it and/or modify it 6: * under the terms of the GNU General Public License as published by the 7: * Free Software Foundation; either version 2 of the License, or (at your 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 9: * 10: * This program is distributed in the hope that it will be useful, but 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13: * for more details. 14: */ 15: 16: #include "pkcs12.h" 17: 18: #include <library.h> 19: #include <utils/debug.h> 20: 21: /** 22: * v * ceiling(len/v) 23: */ 24: #define PKCS12_LEN(len, v) (((len) + v-1) & ~(v-1)) 25: 26: /** 27: * Copy src to dst as many times as possible 28: */ 29: static inline void copy_chunk(chunk_t dst, chunk_t src) 30: { 31: size_t i; 32: 33: for (i = 0; i < dst.len; i++) 34: { 35: dst.ptr[i] = src.ptr[i % src.len]; 36: } 37: } 38: 39: /** 40: * Treat two chunks as integers in network order and add them together. 41: * The result is stored in the first chunk, if the second chunk is longer or the 42: * result overflows this is ignored. 43: */ 44: static void add_chunks(chunk_t a, chunk_t b) 45: { 46: uint16_t sum; 47: uint8_t rem = 0; 48: ssize_t i, j; 49: 50: for (i = a.len - 1, j = b.len -1; i >= 0 && j >= 0; i--, j--) 51: { 52: sum = a.ptr[i] + b.ptr[j] + rem; 53: a.ptr[i] = (u_char)sum; 54: rem = sum >> 8; 55: } 56: for (; i >= 0 && rem; i--) 57: { 58: sum = a.ptr[i] + rem; 59: a.ptr[i] = (u_char)sum; 60: rem = sum >> 8; 61: } 62: } 63: 64: /** 65: * Do the actual key derivation with the given hasher, password and id. 66: */ 67: static bool derive_key(hash_algorithm_t hash, chunk_t unicode, chunk_t salt, 68: uint64_t iterations, char id, chunk_t result) 69: { 70: chunk_t out = result, D, S, P = chunk_empty, I, Ai, B, Ij; 71: hasher_t *hasher; 72: size_t Slen, v, u; 73: uint64_t i; 74: bool success = FALSE; 75: 76: hasher = lib->crypto->create_hasher(lib->crypto, hash); 77: if (!hasher) 78: { 79: DBG1(DBG_ASN, " %N hash algorithm not available", 80: hash_algorithm_names, hash); 81: return FALSE; 82: } 83: switch (hash) 84: { 85: case HASH_MD2: 86: case HASH_MD5: 87: case HASH_SHA1: 88: case HASH_SHA224: 89: case HASH_SHA256: 90: v = 64; 91: break; 92: case HASH_SHA384: 93: case HASH_SHA512: 94: v = 128; 95: break; 96: default: 97: goto end; 98: } 99: u = hasher->get_hash_size(hasher); 100: 101: D = chunk_alloca(v); 102: memset(D.ptr, id, D.len); 103: 104: Slen = PKCS12_LEN(salt.len, v); 105: I = chunk_alloca(Slen + PKCS12_LEN(unicode.len, v)); 106: S = chunk_create(I.ptr, Slen); 107: P = chunk_create(I.ptr + Slen, I.len - Slen); 108: copy_chunk(S, salt); 109: copy_chunk(P, unicode); 110: 111: Ai = chunk_alloca(u); 112: B = chunk_alloca(v); 113: 114: while (TRUE) 115: { 116: if (!hasher->get_hash(hasher, D, NULL) || 117: !hasher->get_hash(hasher, I, Ai.ptr)) 118: { 119: goto end; 120: } 121: for (i = 1; i < iterations; i++) 122: { 123: if (!hasher->get_hash(hasher, Ai, Ai.ptr)) 124: { 125: goto end; 126: } 127: } 128: memcpy(out.ptr, Ai.ptr, min(out.len, Ai.len)); 129: out = chunk_skip(out, Ai.len); 130: if (!out.len) 131: { 132: break; 133: } 134: copy_chunk(B, Ai); 135: /* B = B+1 */ 136: add_chunks(B, chunk_from_chars(0x01)); 137: Ij = chunk_create(I.ptr, v); 138: for (i = 0; i < I.len; i += v, Ij.ptr += v) 139: { /* Ij = Ij + B + 1 */ 140: add_chunks(Ij, B); 141: } 142: } 143: success = TRUE; 144: end: 145: hasher->destroy(hasher); 146: return success; 147: } 148: 149: /* 150: * Described in header 151: */ 152: bool pkcs12_derive_key(hash_algorithm_t hash, chunk_t password, chunk_t salt, 153: uint64_t iterations, pkcs12_key_type_t type, chunk_t key) 154: { 155: chunk_t unicode = chunk_empty; 156: bool success; 157: int i; 158: 159: if (password.len) 160: { /* convert the password to UTF-16BE (without BOM) with 0 terminator */ 161: unicode = chunk_alloca(password.len * 2 + 2); 162: for (i = 0; i < password.len; i++) 163: { 164: unicode.ptr[i * 2] = 0; 165: unicode.ptr[i * 2 + 1] = password.ptr[i]; 166: } 167: unicode.ptr[i * 2] = 0; 168: unicode.ptr[i * 2 + 1] = 0; 169: } 170: 171: success = derive_key(hash, unicode, salt, iterations, type, key); 172: memwipe(unicode.ptr, unicode.len); 173: return success; 174: }