1 /*-
2 * Copyright (c) 2018 Ribose Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <string.h>
28 #include <stdlib.h>
29 #include "mpi.h"
30 #include "hash.h"
31 #include "mem.h"
32 #include "utils.h"
33
34 bignum_t *
mpi2bn(const pgp_mpi_t * val)35 mpi2bn(const pgp_mpi_t *val)
36 {
37 return bn_bin2bn(val->mpi, val->len, NULL);
38 }
39
40 bool
bn2mpi(bignum_t * bn,pgp_mpi_t * val)41 bn2mpi(bignum_t *bn, pgp_mpi_t *val)
42 {
43 return bn_num_bytes(bn, &val->len) && (bn_bn2bin(bn, val->mpi) == 0);
44 }
45
46 size_t
mpi_bits(const pgp_mpi_t * val)47 mpi_bits(const pgp_mpi_t *val)
48 {
49 size_t bits = 0;
50 size_t idx = 0;
51 uint8_t bt;
52
53 for (idx = 0; (idx < val->len) && !val->mpi[idx]; idx++)
54 ;
55
56 if (idx < val->len) {
57 for (bits = (val->len - idx - 1) << 3, bt = val->mpi[idx]; bt; bits++, bt = bt >> 1)
58 ;
59 }
60
61 return bits;
62 }
63
64 size_t
mpi_bytes(const pgp_mpi_t * val)65 mpi_bytes(const pgp_mpi_t *val)
66 {
67 return val->len;
68 }
69
70 bool
mem2mpi(pgp_mpi_t * val,const void * mem,size_t len)71 mem2mpi(pgp_mpi_t *val, const void *mem, size_t len)
72 {
73 if (len > sizeof(val->mpi)) {
74 return false;
75 }
76
77 memcpy(val->mpi, mem, len);
78 val->len = len;
79 return true;
80 }
81
82 void
mpi2mem(const pgp_mpi_t * val,void * mem)83 mpi2mem(const pgp_mpi_t *val, void *mem)
84 {
85 memcpy(mem, val->mpi, val->len);
86 }
87
88 char *
mpi2hex(const pgp_mpi_t * val)89 mpi2hex(const pgp_mpi_t *val)
90 {
91 static const char *hexes = "0123456789abcdef";
92 char * out;
93 size_t len;
94 size_t idx = 0;
95
96 len = mpi_bytes(val);
97 out = (char *) malloc(len * 2 + 1);
98
99 if (!out) {
100 return out;
101 }
102
103 for (size_t i = 0; i < len; i++) {
104 out[idx++] = hexes[val->mpi[i] >> 4];
105 out[idx++] = hexes[val->mpi[i] & 0xf];
106 }
107 out[idx] = '\0';
108 return out;
109 }
110
111 bool
mpi_equal(const pgp_mpi_t * val1,const pgp_mpi_t * val2)112 mpi_equal(const pgp_mpi_t *val1, const pgp_mpi_t *val2)
113 {
114 size_t idx1 = 0;
115 size_t idx2 = 0;
116
117 for (idx1 = 0; (idx1 < val1->len) && !val1->mpi[idx1]; idx1++)
118 ;
119
120 for (idx2 = 0; (idx2 < val2->len) && !val2->mpi[idx2]; idx2++)
121 ;
122
123 return ((val1->len - idx1) == (val2->len - idx2) &&
124 !memcmp(val1->mpi + idx1, val2->mpi + idx2, val1->len - idx1));
125 }
126
127 /* hashes 32-bit length + mpi body (paddded with 0 if high order byte is >= 0x80) */
128 bool
mpi_hash(const pgp_mpi_t * val,pgp_hash_t * hash)129 mpi_hash(const pgp_mpi_t *val, pgp_hash_t *hash)
130 {
131 size_t len;
132 size_t idx;
133 uint8_t padbyte = 0;
134 bool res = true;
135
136 len = mpi_bytes(val);
137 for (idx = 0; (idx < len) && (val->mpi[idx] == 0); idx++)
138 ;
139
140 if (idx >= len) {
141 return pgp_hash_uint32(hash, 0);
142 }
143
144 res = pgp_hash_uint32(hash, len - idx);
145 if (val->mpi[idx] & 0x80) {
146 res &= pgp_hash_add(hash, &padbyte, 1);
147 }
148 res &= pgp_hash_add(hash, val->mpi + idx, len - idx);
149
150 return res;
151 }
152
153 void
mpi_forget(pgp_mpi_t * val)154 mpi_forget(pgp_mpi_t *val)
155 {
156 secure_clear(val, sizeof(*val));
157 val->len = 0;
158 }
159