1 /*
2  * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *
11  * 2.  Redistributions in binary form must reproduce the above copyright notice,
12  *     this list of conditions and the following disclaimer in the documentation
13  *     and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "ecdh_utils.h"
28 #include "types.h"
29 #include "utils.h"
30 #include <cassert>
31 
32 /* Used by ECDH keys. Specifies which hash and wrapping algorithm
33  * to be used (see point 15. of RFC 4880).
34  *
35  * Note: sync with ec_curves.
36  */
37 static const struct ecdh_params_t {
38     pgp_curve_t    curve;    /* Curve ID */
39     pgp_hash_alg_t hash;     /* Hash used by kdf */
40     pgp_symm_alg_t wrap_alg; /* Symmetric algorithm used to wrap KEK*/
41 } ecdh_params[] = {
42   {.curve = PGP_CURVE_NIST_P_256, .hash = PGP_HASH_SHA256, .wrap_alg = PGP_SA_AES_128},
43   {.curve = PGP_CURVE_NIST_P_384, .hash = PGP_HASH_SHA384, .wrap_alg = PGP_SA_AES_192},
44   {.curve = PGP_CURVE_NIST_P_521, .hash = PGP_HASH_SHA512, .wrap_alg = PGP_SA_AES_256},
45   {.curve = PGP_CURVE_BP256, .hash = PGP_HASH_SHA256, .wrap_alg = PGP_SA_AES_128},
46   {.curve = PGP_CURVE_BP384, .hash = PGP_HASH_SHA384, .wrap_alg = PGP_SA_AES_192},
47   {.curve = PGP_CURVE_BP512, .hash = PGP_HASH_SHA512, .wrap_alg = PGP_SA_AES_256},
48   {.curve = PGP_CURVE_25519, .hash = PGP_HASH_SHA256, .wrap_alg = PGP_SA_AES_128},
49   {.curve = PGP_CURVE_P256K1, .hash = PGP_HASH_SHA256, .wrap_alg = PGP_SA_AES_128},
50 };
51 
52 // "Anonymous Sender " in hex
53 static const unsigned char ANONYMOUS_SENDER[] = {0x41, 0x6E, 0x6F, 0x6E, 0x79, 0x6D, 0x6F,
54                                                  0x75, 0x73, 0x20, 0x53, 0x65, 0x6E, 0x64,
55                                                  0x65, 0x72, 0x20, 0x20, 0x20, 0x20};
56 
57 // returns size of data written to other_info
58 size_t
kdf_other_info_serialize(uint8_t other_info[MAX_SP800_56A_OTHER_INFO],const ec_curve_desc_t * ec_curve,const pgp_fingerprint_t & fingerprint,const pgp_hash_alg_t kdf_hash,const pgp_symm_alg_t wrap_alg)59 kdf_other_info_serialize(uint8_t                  other_info[MAX_SP800_56A_OTHER_INFO],
60                          const ec_curve_desc_t *  ec_curve,
61                          const pgp_fingerprint_t &fingerprint,
62                          const pgp_hash_alg_t     kdf_hash,
63                          const pgp_symm_alg_t     wrap_alg)
64 {
65     assert(fingerprint.length >= 20);
66     uint8_t *buf_ptr = &other_info[0];
67 
68     /* KDF-OtherInfo: AlgorithmID
69      *   Current implementation will always use SHA-512 and AES-256 for KEK wrapping
70      */
71     *(buf_ptr++) = ec_curve->OIDhex_len;
72     memcpy(buf_ptr, ec_curve->OIDhex, ec_curve->OIDhex_len);
73     buf_ptr += ec_curve->OIDhex_len;
74     *(buf_ptr++) = PGP_PKA_ECDH;
75     // size of following 3 params (each 1 byte)
76     *(buf_ptr++) = 0x03;
77     // Value reserved for future use
78     *(buf_ptr++) = 0x01;
79     // Hash used with KDF
80     *(buf_ptr++) = kdf_hash;
81     // Algorithm ID used for key wrapping
82     *(buf_ptr++) = wrap_alg;
83 
84     /* KDF-OtherInfo: PartyUInfo
85      *   20 bytes representing "Anonymous Sender "
86      */
87     memcpy(buf_ptr, ANONYMOUS_SENDER, sizeof(ANONYMOUS_SENDER));
88     buf_ptr += sizeof(ANONYMOUS_SENDER);
89 
90     // keep 20, as per spec
91     memcpy(buf_ptr, fingerprint.fingerprint, 20);
92     return (buf_ptr - other_info) + 20 /*anonymous_sender*/;
93 }
94 
95 bool
pad_pkcs7(uint8_t * buf,size_t buf_len,size_t offset)96 pad_pkcs7(uint8_t *buf, size_t buf_len, size_t offset)
97 {
98     if (buf_len <= offset) {
99         // Must have at least 1 byte of padding
100         return false;
101     }
102 
103     const uint8_t pad_byte = buf_len - offset;
104     memset(buf + offset, pad_byte, pad_byte);
105     return true;
106 }
107 
108 bool
unpad_pkcs7(uint8_t * buf,size_t buf_len,size_t * offset)109 unpad_pkcs7(uint8_t *buf, size_t buf_len, size_t *offset)
110 {
111     if (!buf || !offset || !buf_len) {
112         return false;
113     }
114 
115     uint8_t        err = 0;
116     const uint8_t  pad_byte = buf[buf_len - 1];
117     const uint32_t pad_begin = buf_len - pad_byte;
118 
119     // TODO: Still >, <, and <=,==  are not constant time (maybe?)
120     err |= (pad_byte > buf_len);
121     err |= (pad_byte == 0);
122 
123     /* Check if padding is OK */
124     for (size_t c = 0; c < buf_len; c++) {
125         err |= (buf[c] ^ pad_byte) * (pad_begin <= c);
126     }
127 
128     *offset = pad_begin;
129     return (err == 0);
130 }
131 
132 bool
ecdh_set_params(pgp_ec_key_t * key,pgp_curve_t curve_id)133 ecdh_set_params(pgp_ec_key_t *key, pgp_curve_t curve_id)
134 {
135     for (size_t i = 0; i < ARRAY_SIZE(ecdh_params); i++) {
136         if (ecdh_params[i].curve == curve_id) {
137             key->kdf_hash_alg = ecdh_params[i].hash;
138             key->key_wrap_alg = ecdh_params[i].wrap_alg;
139             return true;
140         }
141     }
142 
143     return false;
144 }
145 
146 bool
x25519_tweak_bits(pgp_ec_key_t & key)147 x25519_tweak_bits(pgp_ec_key_t &key)
148 {
149     if (key.x.len != 32) {
150         return false;
151     }
152     /* MPI is big-endian, while raw x25519 key is little-endian */
153     key.x.mpi[31] &= 248; // zero 3 low bits
154     key.x.mpi[0] &= 127;  // zero high bit
155     key.x.mpi[0] |= 64;   // set high - 1 bit
156     return true;
157 }
158 
159 bool
x25519_bits_tweaked(const pgp_ec_key_t & key)160 x25519_bits_tweaked(const pgp_ec_key_t &key)
161 {
162     if (key.x.len != 32) {
163         return false;
164     }
165     return !(key.x.mpi[31] & 7) && (key.x.mpi[0] < 128) && (key.x.mpi[0] >= 64);
166 }
167