aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pbkdf/pgp_s2k/pgp_s2k.h
blob: b2c16d9ed7bc3721fce8cea1296bd7638208868c (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* OpenPGP PBKDF
* (C) 1999-2007,2017 Jack Lloyd
* (C) 2018 Ribose Inc
*
* Distributed under the terms of the Botan license
*/

#ifndef BOTAN_OPENPGP_S2K_H_
#define BOTAN_OPENPGP_S2K_H_

#include <botan/pbkdf.h>
#include <botan/pwdhash.h>
#include <botan/hash.h>

namespace Botan {

/**
* RFC 4880 encodes the iteration count to a single-byte value
*/
uint8_t BOTAN_PUBLIC_API(2,8) RFC4880_encode_count(size_t iterations);

/**
* Decode the iteration count from RFC 4880 encoding
*/
size_t BOTAN_PUBLIC_API(2,8) RFC4880_decode_count(uint8_t encoded_iter);

/**
* Round an arbitrary iteration count to next largest iteration count
* supported by RFC4880 encoding.
*/
inline size_t RFC4880_round_iterations(size_t iterations)
   {
   return RFC4880_decode_count(RFC4880_encode_count(iterations));
   }

/**
* OpenPGP's S2K
*
* See RFC 4880 sections 3.7.1.1, 3.7.1.2, and 3.7.1.3
* If the salt is empty and iterations == 1, "simple" S2K is used
* If the salt is non-empty and iterations == 1, "salted" S2K is used
* If the salt is non-empty and iterations > 1, "iterated" S2K is used
*
* Due to complexities of the PGP S2K algorithm, time-based derivation
* is not supported. So if iterations == 0 and msec.count() > 0, an
* exception is thrown. In the future this may be supported, in which
* case "iterated" S2K will be used and the number of iterations
* performed is returned.
*
* Note that unlike PBKDF2, OpenPGP S2K's "iterations" are defined as
* the number of bytes hashed.
*/
class BOTAN_PUBLIC_API(2,2) OpenPGP_S2K final : public PBKDF
   {
   public:
      /**
      * @param hash the hash function to use
      */
      explicit OpenPGP_S2K(HashFunction* hash) : m_hash(hash) {}

      std::string name() const override
         {
         return "OpenPGP-S2K(" + m_hash->name() + ")";
         }

      PBKDF* clone() const override
         {
         return new OpenPGP_S2K(m_hash->clone());
         }

      size_t pbkdf(uint8_t output_buf[], size_t output_len,
                   const std::string& passphrase,
                   const uint8_t salt[], size_t salt_len,
                   size_t iterations,
                   std::chrono::milliseconds msec) const override;

      /**
      * RFC 4880 encodes the iteration count to a single-byte value
      */
      static uint8_t encode_count(size_t iterations)
         {
         return RFC4880_encode_count(iterations);
         }

      static size_t decode_count(uint8_t encoded_iter)
         {
         return RFC4880_decode_count(encoded_iter);
         }

   private:
      std::unique_ptr<HashFunction> m_hash;
   };

/**
* OpenPGP's S2K
*
* See RFC 4880 sections 3.7.1.1, 3.7.1.2, and 3.7.1.3
* If the salt is empty and iterations == 1, "simple" S2K is used
* If the salt is non-empty and iterations == 1, "salted" S2K is used
* If the salt is non-empty and iterations > 1, "iterated" S2K is used
*
* Note that unlike PBKDF2, OpenPGP S2K's "iterations" are defined as
* the number of bytes hashed.
*/
class BOTAN_PUBLIC_API(2,8) RFC4880_S2K final : public PasswordHash
   {
   public:
      /**
      * @param hash the hash function to use
      * @param the iterations to use (this is rounded due to PGP formatting)
      */
      RFC4880_S2K(HashFunction* hash, size_t iterations);

      std::string to_string() const override;

      size_t iterations() const override { return m_iterations; }

      void derive_key(uint8_t out[], size_t out_len,
                      const char* password, const size_t password_len,
                      const uint8_t salt[], size_t salt_len) const;

   private:
      std::unique_ptr<HashFunction> m_hash;
      size_t m_iterations;
   };

class BOTAN_PUBLIC_API(2,8) RFC4880_S2K_Family final : public PasswordHashFamily
   {
   public:
      RFC4880_S2K_Family(HashFunction* hash) : m_hash(hash) {}

      std::string name() const override;

      std::unique_ptr<PasswordHash> tune(size_t output_len,
                                         std::chrono::milliseconds msec,
                                         size_t max_mem) const override;

      /**
      * Return some default parameter set for this PBKDF that should be good
      * enough for most users. The value returned may change over time as
      * processing power and attacks improve.
      */
      std::unique_ptr<PasswordHash> default_params() const override;

      std::unique_ptr<PasswordHash> from_params(
         size_t iter, size_t, size_t) const override;
   private:
      std::unique_ptr<HashFunction> m_hash;
   };

}

#endif