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
|
/*
20210314
Jan Mojzis
Public domain.
*/
#include "randombytes.h"
#include "cleanup.h"
#include "crypto_hash_sha512.h"
#include "crypto_scalarmult_curve25519.h"
#include "crypto_kem_sntrup761.h"
#include "crypto_kem_sntrup761x25519.h"
#define sntrup761_BYTES crypto_kem_sntrup761_BYTES
#define x25519_BYTES crypto_scalarmult_curve25519_BYTES
#define x25519_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES
#define sx_BYTES sntrup761_BYTES + x25519_BYTES
#define sntrup761_PUBLICKEYBYTES crypto_kem_sntrup761_PUBLICKEYBYTES
#define sntrup761_SECRETKEYBYTES crypto_kem_sntrup761_SECRETKEYBYTES
#define sx_PUBLICKEYBYTES sntrup761_PUBLICKEYBYTES + x25519_BYTES
#define sx_SECRETKEYBYTES sntrup761_SECRETKEYBYTES + x25519_SCALARBYTES
static unsigned char returnmask(int x) {
unsigned long long ret = 1ULL;
ret <<= 8 * sizeof(int);
ret -= (unsigned long long)(unsigned int)x;
ret >>= 8 * sizeof(int);
return ret - 1;
}
int crypto_kem_sntrup761x25519_tinyssh_enc(unsigned char *c,
unsigned char *k,
const unsigned char *pk) {
int r = 0;
long long i;
unsigned char onetimesk[x25519_SCALARBYTES];
unsigned char buf[sx_BYTES];
unsigned char tmp[sx_BYTES];
unsigned char b;
/* sntrup761 */
r |= crypto_kem_sntrup761_enc(c, buf, pk);
pk += crypto_kem_sntrup761_PUBLICKEYBYTES;
c += crypto_kem_sntrup761_CIPHERTEXTBYTES;
/* x25519 */
randombytes(onetimesk, sizeof onetimesk);
r |= crypto_scalarmult_curve25519_base(/*onetimepk*/ c, onetimesk);
r |= crypto_scalarmult_curve25519(buf + sntrup761_BYTES, onetimesk, pk);
/* if something fails, fill the buffer with random data */
randombytes(tmp, sizeof tmp);
b = returnmask(r);
for (i = 0; i < sx_BYTES; ++i) tmp[i] = b & (tmp[i] ^ buf[i]);
for (i = 0; i < sx_BYTES; ++i) buf[i] ^= tmp[i];
/* hash together sntrup459176 KEM-key and x25519 shared secret */
crypto_hash_sha512(k, buf, sizeof buf);
/* cleanup */
cleanup(buf);
cleanup(onetimesk);
return r;
}
int crypto_kem_sntrup761x25519_tinyssh_dec(unsigned char *k,
const unsigned char *c,
const unsigned char *sk) {
int r = 0;
long long i;
unsigned char buf[sx_BYTES];
unsigned char tmp[sx_BYTES];
unsigned char b;
/* sntrup761 */
r |= crypto_kem_sntrup761_dec(buf, c, sk);
sk += crypto_kem_sntrup761_SECRETKEYBYTES;
c += crypto_kem_sntrup761_CIPHERTEXTBYTES;
/* x25519 */
r |= crypto_scalarmult_curve25519(buf + sntrup761_BYTES, sk, c);
/* if something fails, fill the buffer with random data */
randombytes(tmp, sizeof tmp);
b = returnmask(r);
for (i = 0; i < sx_BYTES; ++i) tmp[i] = b & (tmp[i] ^ buf[i]);
for (i = 0; i < sx_BYTES; ++i) buf[i] ^= tmp[i];
/* hash together sntrup459176 KEM-key and x25519 shared secret */
crypto_hash_sha512(k, buf, sizeof buf);
/* cleanup */
cleanup(buf);
return r;
}
int crypto_kem_sntrup761x25519_tinyssh_keypair(unsigned char *pk,
unsigned char *sk) {
int r = 0;
long long i;
unsigned char b;
/* sntrup761 */
r |= crypto_kem_sntrup761_keypair(pk, sk);
/* x25519 */
randombytes(sk + sntrup761_SECRETKEYBYTES, x25519_SCALARBYTES);
r |= crypto_scalarmult_curve25519_base(pk + sntrup761_PUBLICKEYBYTES,
sk + sntrup761_SECRETKEYBYTES);
b = ~returnmask(r);
for (i = 0; i < sx_PUBLICKEYBYTES; ++i) pk[i] &= b;
for (i = 0; i < sx_SECRETKEYBYTES; ++i) sk[i] &= b;
return r;
}
|