Annotation of embedaddon/strongswan/src/libstrongswan/credentials/containers/pkcs12.c, revision 1.1.1.1

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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>