aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/kdf/prf_x942/prf_x942.cpp
blob: 5ca0f01ffee2acd757bfe27c8ead3cb247183ce1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
* X9.42 PRF
* (C) 1999-2007 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/kdf_utils.h>
#include <botan/prf_x942.h>
#include <botan/der_enc.h>
#include <botan/oids.h>
#include <botan/hash.h>
#include <botan/loadstor.h>
#include <algorithm>

namespace Botan {

BOTAN_REGISTER_KDF_NAMED_1STR(X942_PRF, "X9.42-PRF");

namespace {

/*
* Encode an integer as an OCTET STRING
*/
std::vector<byte> encode_x942_int(u32bit n)
   {
   byte n_buf[4] = { 0 };
   store_be(n, n_buf);
   return DER_Encoder().encode(n_buf, 4, OCTET_STRING).get_contents_unlocked();
   }

}

size_t X942_PRF::kdf(byte key[], size_t key_len,
                     const byte secret[], size_t secret_len,
                     const byte salt[], size_t salt_len) const
   {
   std::unique_ptr<HashFunction> hash(make_a<HashFunction>("SHA-160"));
   const OID kek_algo(m_key_wrap_oid);

   secure_vector<byte> h;
   size_t offset = 0;
   u32bit counter = 1;

   while(offset != key_len && counter)
      {
      hash->update(secret, secret_len);

      hash->update(
         DER_Encoder().start_cons(SEQUENCE)

            .start_cons(SEQUENCE)
               .encode(kek_algo)
               .raw_bytes(encode_x942_int(counter))
            .end_cons()

            .encode_if(salt_len != 0,
               DER_Encoder()
                  .start_explicit(0)
                     .encode(salt, salt_len, OCTET_STRING)
                  .end_explicit()
               )

            .start_explicit(2)
               .raw_bytes(encode_x942_int(static_cast<u32bit>(8 * key_len)))
            .end_explicit()

         .end_cons().get_contents()
         );

      hash->final(h);
      const size_t copied = std::min(h.size(), key_len - offset);
      copy_mem(&key[offset], &h[0], copied);
      offset += copied;

      ++counter;
      }

   return offset;
   }

/*
* X9.42 Constructor
*/
X942_PRF::X942_PRF(const std::string& oid)
   {
   if(OIDS::have_oid(oid))
      m_key_wrap_oid = OIDS::lookup(oid).as_string();
   else
      m_key_wrap_oid = oid;
   }

}