Skip to content

Commit 2dc0f45

Browse files
committed
payment protocol encryption/decryption with tests
1 parent a56b66e commit 2dc0f45

13 files changed

+723
-150
lines changed

BRAddress.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ size_t BRAddressFromScriptSig(char *addr, size_t addrLen, const uint8_t *script,
315315
}
316316

317317
// writes the scriptPubKey for addr to script
318-
// returns the number of bytes written or scripLen needed if script is NULL
318+
// returns the number of bytes written or scriptLen needed if script is NULL
319319
size_t BRAddressScriptPubKey(uint8_t *script, size_t scriptLen, const char *addr)
320320
{
321321
static uint8_t pubkeyAddress = BITCOIN_PUBKEY_ADDRESS, scriptAddress = BITCOIN_SCRIPT_ADDRESS;

BRAddress.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
#include "BRCrypto.h"
2929
#include <string.h>
30+
#include <stddef.h>
31+
#include <inttypes.h>
3032

3133
#ifdef __cplusplus
3234
extern "C" {
@@ -89,7 +91,7 @@ size_t BRAddressFromScriptPubKey(char *addr, size_t addrLen, const uint8_t *scri
8991
size_t BRAddressFromScriptSig(char *addr, size_t addrLen, const uint8_t *script, size_t scriptLen);
9092

9193
// writes the scriptPubKey for addr to script
92-
// returns the number of bytes written or scripLen needed if script is NULL
94+
// returns the number of bytes written or scriptLen needed if script is NULL
9395
size_t BRAddressScriptPubKey(uint8_t *script, size_t scriptLen, const char *addr);
9496

9597
// returns true if addr is a valid bitcoin address

BRArray.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,8 @@ extern "C" {
5656
// array_clear(myArray); // myArray is now empty
5757
// array_free(myArray); // free memory allocated for myArray
5858
//
59-
// note:
60-
// when new items are added to an array past its current capacity, its memory location may change, so other references
61-
// to it or its members must be updated
59+
// NOTE: when new items are added to an array past its current capacity, its memory location may change, so other
60+
// references to it or its members must be updated
6261

6362
#define array_new(array, capacity) do {\
6463
size_t _array_cap = (capacity);\

BRBIP38Key.c

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ int BRBIP38KeyIsValid(const char *bip38Key)
207207
uint8_t data[39];
208208

209209
assert(bip38Key != NULL);
210+
210211
if (BRBase58CheckDecode(data, sizeof(data), bip38Key) != 39) return 0; // invalid length
211212

212213
uint16_t prefix = UInt16GetBE(data);
@@ -232,6 +233,7 @@ int BRKeySetBIP38Key(BRKey *key, const char *bip38Key, const char *passphrase)
232233
assert(key != NULL);
233234
assert(bip38Key != NULL);
234235
assert(passphrase != NULL);
236+
235237
if (BRBase58CheckDecode(data, sizeof(data), bip38Key) != 39) return 0; // invalid length
236238

237239
uint16_t prefix = UInt16GetBE(data);
@@ -327,6 +329,48 @@ void BRKeySetBIP38ItermediateCode(BRKey *key, const char *code, const uint8_t *s
327329
// returns number of bytes written to bip38Key including NULL terminator or total bip38KeyLen needed if bip38Key is NULL
328330
size_t BRKeyBIP38Key(BRKey *key, char *bip38Key, size_t bip38KeyLen, const char *passphrase)
329331
{
330-
// TODO: XXX implement
331-
return 0;
332+
uint16_t prefix = BIP38_NOEC_PREFIX;
333+
uint8_t buf[39], flag = BIP38_NOEC_FLAG;
334+
uint32_t salt;
335+
size_t off = 0;
336+
BRAddress address;
337+
UInt512 derived;
338+
UInt256 hash, derived1, derived2;
339+
UInt128 encrypted1, encrypted2;
340+
341+
if (! bip38Key) return 43*138/100 + 1; // 43bytes*log(256)/log(58), rounded up
342+
343+
assert(key != NULL);
344+
assert(passphrase != NULL);
345+
346+
if (key->compressed) flag |= BIP38_COMPRESSED_FLAG;
347+
BRKeyAddress(key, address.s, sizeof(address));
348+
BRSHA256_2(&hash, address.s, strlen(address.s));
349+
salt = hash.u32[0];
350+
351+
BRScrypt(&derived, sizeof(derived), passphrase, strlen(passphrase), &salt, sizeof(salt),
352+
BIP38_SCRYPT_N, BIP38_SCRYPT_R, BIP38_SCRYPT_P);
353+
derived1 = *(UInt256 *)&derived, derived2 = *(UInt256 *)&derived.u64[4];
354+
355+
// enctryped1 = AES256Encrypt(privkey[0...15] xor derived1[0...15], derived2)
356+
encrypted1.u64[0] = key->secret.u64[0] ^ derived1.u64[0];
357+
encrypted1.u64[1] = key->secret.u64[1] ^ derived1.u64[1];
358+
_BRAES256ECBEncrypt(&derived2, &encrypted1);
359+
360+
// encrypted2 = AES256Encrypt(privkey[16...31] xor derived1[16...31], derived2)
361+
encrypted2.u64[0] = key->secret.u64[2] ^ derived1.u64[2];
362+
encrypted2.u64[1] = key->secret.u64[3] ^ derived1.u64[3];
363+
_BRAES256ECBEncrypt(&derived2, &encrypted2);
364+
365+
UInt16SetBE(&buf[off], prefix);
366+
off += sizeof(prefix);
367+
buf[off] = flag;
368+
off += sizeof(flag);
369+
UInt32SetBE(&buf[off], UInt32GetBE(&salt));
370+
off += sizeof(salt);
371+
UInt128Set(&buf[off], encrypted1);
372+
off += sizeof(encrypted1);
373+
UInt128Set(&buf[off], encrypted2);
374+
off += sizeof(encrypted2);
375+
return BRBase58CheckEncode(bip38Key, bip38KeyLen, buf, off);
332376
}

BRCrypto.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ void BRHash160(void *md20, const void *data, size_t len)
391391

392392
assert(md20 != NULL);
393393
assert(data != NULL || len == 0);
394+
394395
BRSHA256(t, data, len);
395396
BRRMD160(md20, t, sizeof(t));
396397
}
@@ -507,6 +508,7 @@ void BRHMAC(void *mac, void (*hash)(void *, const void *, size_t), size_t hashLe
507508
assert(hashLen > 0 && (hashLen % 4) == 0);
508509
assert(key != NULL || keyLen == 0);
509510
assert(data != NULL || dataLen == 0);
511+
510512
if (keyLen > blockLen) hash(k, key, keyLen), key = k, keyLen = sizeof(k);
511513
memset(kipad, 0, blockLen);
512514
memcpy(kipad, key, keyLen);
@@ -523,6 +525,51 @@ void BRHMAC(void *mac, void (*hash)(void *, const void *, size_t), size_t hashLe
523525
memset(kopad, 0, blockLen);
524526
}
525527

528+
// hmac-drbg with no prediction resistance or additional input
529+
// K and V must point to buffers of size hashLen, and ps (personalization string) may be NULL
530+
// to generate additional drbg output, use K and V from the previous call, and set seed, nonce and ps to NULL
531+
void BRHMACDRBG(void *out, size_t outLen, void *K, void *V, void (*hash)(void *, const void *, size_t), size_t hashLen,
532+
const void *seed, size_t seedLen, const void *nonce, size_t nonceLen, const void *ps, size_t psLen)
533+
{
534+
size_t i, bufLen = hashLen + 1 + seedLen + nonceLen + psLen;
535+
uint8_t buf[bufLen];
536+
537+
assert(out != NULL || outLen == 0);
538+
assert(K != NULL);
539+
assert(V != NULL);
540+
assert(hash != NULL);
541+
assert(hashLen > 0 && (hashLen % 4) == 0);
542+
assert(seed != NULL || seedLen == 0);
543+
assert(nonce != NULL || nonceLen == 0);
544+
assert(ps != NULL || psLen == 0);
545+
546+
if (seed || nonce || ps) { // K = [0x00, 0x00, ... 0x00], V = [0x01, 0x01, ... 0x01]
547+
for (i = 0; i < hashLen; i++) ((uint8_t *)K)[i] = 0x00, ((uint8_t *)V)[i] = 0x01;
548+
}
549+
550+
memcpy(buf, V, hashLen);
551+
buf[hashLen] = 0x00;
552+
memcpy(&buf[hashLen + 1], seed, seedLen);
553+
memcpy(&buf[hashLen + 1 + seedLen], nonce, nonceLen);
554+
memcpy(&buf[hashLen + 1 + seedLen + nonceLen], ps, psLen);
555+
BRHMAC(K, hash, hashLen, K, hashLen, buf, bufLen); // K = HMAC(K, V || 0x00 || entropy || nonce || ps)
556+
BRHMAC(V, hash, hashLen, K, hashLen, V, hashLen); // V = HMAC(K, V)
557+
558+
if (seed || nonce || ps) {
559+
memcpy(buf, V, hashLen);
560+
buf[hashLen] = 0x01;
561+
BRHMAC(K, hash, hashLen, K, hashLen, buf, bufLen); // K = HMAC(K, V || 0x01 || entropy || nonce || ps)
562+
BRHMAC(V, hash, hashLen, K, hashLen, V, hashLen); // V = HMAC(K, V)
563+
}
564+
565+
memset(buf, 0, bufLen);
566+
567+
for (i = 0; i*hashLen < outLen; i++) {
568+
BRHMAC(V, hash, hashLen, K, hashLen, V, hashLen); // V = HMAC(K, V)
569+
memcpy((uint8_t *)out + i*hashLen, V, (i*hashLen + hashLen <= outLen) ? hashLen : outLen % hashLen);
570+
}
571+
}
572+
526573
static void _BRPoly1305Compress(uint32_t h[5], const void *key32, const void *data, size_t len, int final)
527574
{
528575
uint32_t x[4], b, t0, t1, t2, t3, t4, r0, r1, r2, r3, r4;
@@ -590,7 +637,7 @@ static void _BRPoly1305Compress(uint32_t h[5], const void *key32, const void *da
590637
}
591638

592639
// poly1305 authenticator: https://tools.ietf.org/html/rfc7539
593-
// must use constant time mem comparison when verifying mac to defend against timing attacks
640+
// NOTE: must use constant time mem comparison when verifying mac to defend against timing attacks
594641
void BRPoly1305(void *mac16, const void *key32, const void *data, size_t len)
595642
{
596643
uint32_t h[5] = { 0, 0, 0, 0, 0 };
@@ -697,7 +744,7 @@ size_t BRChacha20Poly1305AEADDecrypt(void *out, size_t outLen, const void *key32
697744
uint32_t h[5] = { 0, 0, 0, 0, 0 }, mac[4];
698745

699746
if (! out) return (dataLen < 16) ? 0 : dataLen - 16;
700-
if (dataLen < 16 || (dataLen - 16)/64 >= UINT32_MAX || outLen < dataLen - 16) return 0;
747+
if (dataLen < 16 || (dataLen - 16)/64 >= UINT32_MAX || outLen + 16 < dataLen) return 0;
701748

702749
assert(key32 != NULL);
703750
assert(nonce12 != NULL);
@@ -743,6 +790,7 @@ void BRPBKDF2(void *dk, size_t dkLen, void (*hash)(void *, const void *, size_t)
743790
assert(pw != NULL || pwLen == 0);
744791
assert(salt != NULL || saltLen == 0);
745792
assert(rounds > 0);
793+
746794
memcpy(s, salt, saltLen);
747795

748796
for (i = 0; i < (dkLen + hashLen - 1)/hashLen; i++) {
@@ -817,6 +865,7 @@ void BRScrypt(void *dk, size_t dkLen, const void *pw, size_t pwLen, const void *
817865
assert(n > 0);
818866
assert(r > 0);
819867
assert(p > 0);
868+
820869
BRPBKDF2(b, sizeof(b), BRSHA256, 32, pw, pwLen, salt, saltLen, 1);
821870

822871
for (int i = 0; i < p; i++) {

BRCrypto.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,14 @@ uint32_t BRMurmur3_32(const void *data, size_t len, uint32_t seed);
6161
void BRHMAC(void *mac, void (*hash)(void *, const void *, size_t), size_t hashLen, const void *key, size_t keyLen,
6262
const void *data, size_t dataLen);
6363

64+
// hmac-drbg with no prediction resistance or additional input
65+
// K and V must point to buffers of size hashLen, and ps (personalization string) may be NULL
66+
// to generate additional drbg output, use K and V from the previous call, and set seed, nonce and ps to NULL
67+
void BRHMACDRBG(void *out, size_t outLen, void *K, void *V, void (*hash)(void *, const void *, size_t), size_t hashLen,
68+
const void *seed, size_t seedLen, const void *nonce, size_t nonceLen, const void *ps, size_t psLen);
69+
6470
// poly1305 authenticator: https://tools.ietf.org/html/rfc7539
65-
// must use constant time mem comparison when verifying mac to defend against timing attacks
71+
// NOTE: must use constant time mem comparison when verifying mac to defend against timing attacks
6672
void BRPoly1305(void *mac16, const void *key32, const void *data, size_t len);
6773

6874
// chacha20 stream cypher: https://cr.yp.to/chacha.html

BRKey.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ int BRPrivKeyIsValid(const char *privKey)
124124
int r = 0;
125125

126126
assert(privKey != NULL);
127+
127128
dataLen = BRBase58CheckDecode(data, sizeof(data), privKey);
128129
strLen = strlen(privKey);
129130

@@ -155,6 +156,7 @@ int BRKeySetSecret(BRKey *key, const UInt256 *secret, int compressed)
155156
{
156157
assert(key != NULL);
157158
assert(secret != NULL);
159+
158160
pthread_once(&_ctx_once, _ctx_init);
159161
BRKeyClean(key);
160162
key->secret = UInt256Get(secret);
@@ -172,6 +174,7 @@ int BRKeySetPrivKey(BRKey *key, const char *privKey)
172174
#if BITCOIN_TESTNET
173175
version = BITCOIN_PRIVKEY_TEST;
174176
#endif
177+
175178
assert(key != NULL);
176179
assert(privKey != NULL);
177180

@@ -211,6 +214,7 @@ int BRKeySetPubKey(BRKey *key, const uint8_t *pubKey, size_t pkLen)
211214
assert(key != NULL);
212215
assert(pubKey != NULL);
213216
assert(pkLen == 33 || pkLen == 65);
217+
214218
pthread_once(&_ctx_once, _ctx_init);
215219
BRKeyClean(key);
216220
memcpy(key->pubKey, pubKey, pkLen);
@@ -219,12 +223,12 @@ int BRKeySetPubKey(BRKey *key, const uint8_t *pubKey, size_t pkLen)
219223
}
220224

221225
// writes the private key to privKey and returns the number of bytes writen, or pkLen needed if privKey is NULL
226+
// returns 0 on failure
222227
size_t BRKeyPrivKey(const BRKey *key, char *privKey, size_t pkLen)
223228
{
224229
uint8_t data[34];
225230

226231
assert(key != NULL);
227-
assert(privKey != NULL || pkLen == 0);
228232

229233
if (secp256k1_ec_seckey_verify(_ctx, key->secret.u8)) {
230234
data[0] = BITCOIN_PRIVKEY;
@@ -250,7 +254,6 @@ size_t BRKeyPubKey(BRKey *key, void *pubKey, size_t pkLen)
250254
secp256k1_pubkey pk;
251255

252256
assert(key != NULL);
253-
assert(pubKey != NULL || pkLen == 0);
254257

255258
if (memcmp(key->pubKey, empty, size) == 0 && secp256k1_ec_pubkey_create(_ctx, &pk, key->secret.u8)) {
256259
secp256k1_ec_pubkey_serialize(_ctx, key->pubKey, &size, &pk,
@@ -281,6 +284,7 @@ size_t BRKeyAddress(BRKey *key, char *addr, size_t addrLen)
281284
uint8_t data[21];
282285

283286
assert(key != NULL);
287+
284288
hash = BRKeyHash160(key);
285289
data[0] = BITCOIN_PUBKEY_ADDRESS;
286290
#if BITCOIN_TESTNET
@@ -297,6 +301,7 @@ size_t BRKeyAddress(BRKey *key, char *addr, size_t addrLen)
297301
}
298302

299303
// signs md with key and writes signature to sig and returns the number of bytes written or sigLen needed if sig is NULL
304+
// returns 0 on failure
300305
size_t BRKeySign(const BRKey *key, void *sig, size_t sigLen, UInt256 md)
301306
{
302307
secp256k1_ecdsa_signature s;
@@ -322,6 +327,7 @@ int BRKeyVerify(BRKey *key, UInt256 md, const void *sig, size_t sigLen)
322327
assert(key != NULL);
323328
assert(sig != NULL || sigLen == 0);
324329
assert(sigLen > 0);
330+
325331
len = BRKeyPubKey(key, NULL, 0);
326332

327333
if (len > 0 && secp256k1_ec_pubkey_parse(_ctx, &pk, key->pubKey, len) &&

BRKey.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ int BRKeySetPrivKey(BRKey *key, const char *privKey);
7676
int BRKeySetPubKey(BRKey *key, const uint8_t *pubKey, size_t pkLen);
7777

7878
// writes the private key to privKey and returns the number of bytes writen, or pkLen needed if privKey is NULL
79+
// returns 0 on failure
7980
size_t BRKeyPrivKey(const BRKey *key, char *privKey, size_t pkLen);
8081

8182
// writes the public key to pubKey and returns the number of bytes written, or pkLen needed if pubKey is NULL
@@ -89,6 +90,7 @@ UInt160 BRKeyHash160(BRKey *key);
8990
size_t BRKeyAddress(BRKey *key, char *addr, size_t addrLen);
9091

9192
// signs md with key and writes signature to sig and returns the number of bytes written or sigLen needed if sig is NULL
93+
// returns 0 on failure
9294
size_t BRKeySign(const BRKey *key, void *sig, size_t sigLen, UInt256 md);
9395

9496
// returns true if the signature for md is verified to have been made by key

0 commit comments

Comments
 (0)