This enables SSH ECDSA public key authentication.pull/25/head
parent
c58d4e03c5
commit
7c58fc11a4
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "nist256p1.h"
|
||||
|
||||
const ecdsa_curve nist256p1 = {
|
||||
/* .prime */ {
|
||||
/*.val =*/ {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff}
|
||||
},
|
||||
|
||||
/* G */ {
|
||||
/*.x =*/{/*.val =*/{0x1898c296, 0x1284e517, 0x1eb33a0f, 0xdf604b, 0x2440f277, 0x339b958e, 0x4247f8b, 0x347cb84b, 0x6b17}},
|
||||
/*.y =*/{/*.val =*/{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da, 0xf9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86, 0x4fe3}}
|
||||
},
|
||||
|
||||
/* order */ {
|
||||
/*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc, 0x3fffffff, 0xfff, 0x3fffc000, 0xffff}
|
||||
},
|
||||
|
||||
/* a */ {
|
||||
/*.val =*/{0x3ffffffc, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff}
|
||||
}
|
||||
#if USE_PRECOMPUTED_CP
|
||||
,
|
||||
/* cp */ {
|
||||
#include "nist256p1.table"
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Tomas Dzetkulic
|
||||
* Copyright (c) 2013-2014 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __NIST256P1_H__
|
||||
#define __NIST256P1_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ecdsa.h"
|
||||
|
||||
extern const ecdsa_curve nist256p1;
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,304 @@
|
||||
import ctypes as c
|
||||
import random
|
||||
import ecdsa
|
||||
import hashlib
|
||||
import subprocess
|
||||
import binascii
|
||||
import pytest
|
||||
import os
|
||||
|
||||
|
||||
def bytes2num(s):
|
||||
res = 0
|
||||
for i, b in enumerate(reversed(bytearray(s))):
|
||||
res += b << (i * 8)
|
||||
return res
|
||||
|
||||
|
||||
curves = {
|
||||
'nist256p1': ecdsa.curves.NIST256p,
|
||||
'secp256k1': ecdsa.curves.SECP256k1
|
||||
}
|
||||
|
||||
random_iters = int(os.environ.get('ITERS', 1))
|
||||
|
||||
scons_file = '''
|
||||
srcs = 'ecdsa bignum secp256k1 nist256p1 sha2 rand hmac ripemd160 base58'
|
||||
srcs = [(s + '.c') for s in srcs.split()]
|
||||
flags = ('-Os -g -W -Wall -Wextra -Wimplicit-function-declaration '
|
||||
'-Wredundant-decls -Wstrict-prototypes -Wundef -Wshadow '
|
||||
'-Wpointer-arith -Wformat -Wreturn-type -Wsign-compare -Wmultichar '
|
||||
'-Wformat-nonliteral -Winit-self -Wuninitialized -Wformat-security '
|
||||
'-Werror -Wno-sequence-point ')
|
||||
SharedLibrary('ecdsa', srcs, CCFLAGS=flags)
|
||||
'''
|
||||
open('SConstruct', 'w').write(scons_file)
|
||||
|
||||
subprocess.check_call('scons -s', shell=True)
|
||||
lib = c.cdll.LoadLibrary('./libecdsa.so')
|
||||
|
||||
lib.get_curve_by_name.restype = c.c_void_p
|
||||
|
||||
BIGNUM = c.c_uint32 * 9
|
||||
|
||||
|
||||
class Random(random.Random):
|
||||
def randbytes(self, n):
|
||||
buf = (c.c_uint8 * n)()
|
||||
for i in range(n):
|
||||
buf[i] = self.randrange(0, 256)
|
||||
return buf
|
||||
|
||||
def randpoint(self, curve):
|
||||
k = self.randrange(0, curve.order)
|
||||
return k * curve.generator
|
||||
|
||||
|
||||
def int2bn(x, bn_type=BIGNUM):
|
||||
b = bn_type()
|
||||
b._int = x
|
||||
for i in range(len(b)):
|
||||
b[i] = x % (1 << 30)
|
||||
x = x >> 30
|
||||
return b
|
||||
|
||||
|
||||
def bn2int(b):
|
||||
x = 0
|
||||
for i in range(len(b)):
|
||||
x += (b[i] << (30 * i))
|
||||
return x
|
||||
|
||||
|
||||
@pytest.fixture(params=range(random_iters))
|
||||
def r(request):
|
||||
seed = request.param
|
||||
return Random(seed + int(os.environ.get('SEED', 0)))
|
||||
|
||||
|
||||
@pytest.fixture(params=list(sorted(curves)))
|
||||
def curve(request):
|
||||
name = request.param
|
||||
curve_ptr = lib.get_curve_by_name(name)
|
||||
assert curve_ptr, 'curve {} not found'.format(name)
|
||||
curve_obj = curves[name]
|
||||
curve_obj.ptr = c.c_void_p(curve_ptr)
|
||||
curve_obj.p = curve_obj.curve.p() # shorthand
|
||||
return curve_obj
|
||||
|
||||
|
||||
def test_inverse(curve, r):
|
||||
x = r.randrange(1, curve.p)
|
||||
y = int2bn(x)
|
||||
lib.bn_inverse(y, int2bn(curve.p))
|
||||
y = bn2int(y)
|
||||
y_ = ecdsa.numbertheory.inverse_mod(x, curve.p)
|
||||
assert y == y_
|
||||
|
||||
|
||||
def test_inverse(curve, r):
|
||||
x = r.randrange(0, 2*curve.p)
|
||||
y = int2bn(x)
|
||||
lib.bn_mult_half(y, int2bn(curve.p))
|
||||
y = bn2int(y)
|
||||
if y > curve.p:
|
||||
y -= curve.p
|
||||
half = ecdsa.numbertheory.inverse_mod(2, curve.p)
|
||||
assert y == (x * half) % curve.p
|
||||
|
||||
|
||||
def test_subtractmod(curve, r):
|
||||
x = r.randrange(0, 2 ** 256)
|
||||
y = r.randrange(0, 2 ** 256)
|
||||
z = int2bn(0)
|
||||
lib.bn_subtractmod(int2bn(x), int2bn(y), z, int2bn(curve.p))
|
||||
z = bn2int(z)
|
||||
z_ = x + 2*curve.p - y
|
||||
assert z == z_
|
||||
|
||||
|
||||
def test_subtract2(r):
|
||||
x = r.randrange(0, 2 ** 256)
|
||||
y = r.randrange(0, 2 ** 256)
|
||||
x, y = max(x, y), min(x, y)
|
||||
z = int2bn(0)
|
||||
lib.bn_subtract(int2bn(x), int2bn(y), z)
|
||||
z = bn2int(z)
|
||||
z_ = x - y
|
||||
assert z == z_
|
||||
|
||||
|
||||
def test_addmod(curve, r):
|
||||
x = r.randrange(0, 2 ** 256)
|
||||
y = r.randrange(0, 2 ** 256)
|
||||
z_ = (x + y) % curve.p
|
||||
z = int2bn(x)
|
||||
lib.bn_addmod(z, int2bn(y), int2bn(curve.p))
|
||||
z = bn2int(z)
|
||||
|
||||
assert z == z_
|
||||
|
||||
|
||||
def test_multiply(curve, r):
|
||||
k = r.randrange(0, 2 * curve.p)
|
||||
x = r.randrange(0, 2 * curve.p)
|
||||
z = (k * x) % curve.p
|
||||
k = int2bn(k)
|
||||
z_ = int2bn(x)
|
||||
p_ = int2bn(curve.p)
|
||||
lib.bn_multiply(k, z_, p_)
|
||||
z_ = bn2int(z_)
|
||||
assert z_ < 2*curve.p
|
||||
if z_ >= curve.p:
|
||||
z_ = z_ - curve.p
|
||||
assert z_ == z
|
||||
|
||||
|
||||
def test_multiply1(curve, r):
|
||||
k = r.randrange(0, 2 * curve.p)
|
||||
x = r.randrange(0, 2 * curve.p)
|
||||
kx = k * x
|
||||
res = int2bn(0, bn_type=(c.c_uint32 * 18))
|
||||
lib.bn_multiply_long(int2bn(k), int2bn(x), res)
|
||||
res = bn2int(res)
|
||||
assert res == kx
|
||||
|
||||
|
||||
def test_multiply2(curve, r):
|
||||
x = int2bn(0)
|
||||
s = r.randrange(0, 2 ** 526)
|
||||
res = int2bn(s, bn_type=(c.c_uint32 * 18))
|
||||
prime = int2bn(curve.p)
|
||||
lib.bn_multiply_reduce(x, res, prime)
|
||||
|
||||
x = bn2int(x)
|
||||
x_ = s % curve.p
|
||||
|
||||
assert x == x_
|
||||
|
||||
|
||||
def test_fast_mod(curve, r):
|
||||
x = r.randrange(0, 128*curve.p)
|
||||
y = int2bn(x)
|
||||
lib.bn_fast_mod(y, int2bn(curve.p))
|
||||
y = bn2int(y)
|
||||
assert y < 2*curve.p
|
||||
if y >= curve.p:
|
||||
y -= curve.p
|
||||
assert x % curve.p == y
|
||||
|
||||
|
||||
def test_mod(curve, r):
|
||||
x = r.randrange(0, 2*curve.p)
|
||||
y = int2bn(x)
|
||||
lib.bn_mod(y, int2bn(curve.p))
|
||||
assert bn2int(y) == x % curve.p
|
||||
|
||||
POINT = BIGNUM * 2
|
||||
to_POINT = lambda p: POINT(int2bn(p.x()), int2bn(p.y()))
|
||||
from_POINT = lambda p: (bn2int(p[0]), bn2int(p[1]))
|
||||
|
||||
JACOBIAN = BIGNUM * 3
|
||||
to_JACOBIAN = lambda jp: JACOBIAN(int2bn(jp[0]), int2bn(jp[1]), int2bn(jp[2]))
|
||||
from_JACOBIAN = lambda p: (bn2int(p[0]), bn2int(p[1]), bn2int(p[2]))
|
||||
|
||||
|
||||
def test_point_multiply(curve, r):
|
||||
p = r.randpoint(curve)
|
||||
k = r.randrange(0, 2 ** 256)
|
||||
kp = k * p
|
||||
res = POINT(int2bn(0), int2bn(0))
|
||||
lib.point_multiply(curve.ptr, int2bn(k), to_POINT(p), res)
|
||||
res = from_POINT(res)
|
||||
assert res == (kp.x(), kp.y())
|
||||
|
||||
|
||||
def test_point_add(curve, r):
|
||||
p1 = r.randpoint(curve)
|
||||
p2 = r.randpoint(curve)
|
||||
#print '-' * 80
|
||||
q = p1 + p2
|
||||
q1 = to_POINT(p1)
|
||||
q2 = to_POINT(p2)
|
||||
lib.point_add(curve.ptr, q1, q2)
|
||||
q_ = from_POINT(q2)
|
||||
assert q_ == (q.x(), q.y())
|
||||
|
||||
|
||||
def test_point_double(curve, r):
|
||||
p = r.randpoint(curve)
|
||||
q = p.double()
|
||||
q_ = to_POINT(p)
|
||||
lib.point_double(curve.ptr, q_)
|
||||
q_ = from_POINT(q_)
|
||||
assert q_ == (q.x(), q.y())
|
||||
|
||||
|
||||
def test_point_to_jacobian(curve, r):
|
||||
p = r.randpoint(curve)
|
||||
jp = JACOBIAN()
|
||||
lib.curve_to_jacobian(to_POINT(p), jp, int2bn(curve.p))
|
||||
jx, jy, jz = from_JACOBIAN(jp)
|
||||
assert jx == (p.x() * jz ** 2) % curve.p
|
||||
assert jy == (p.y() * jz ** 3) % curve.p
|
||||
|
||||
q = POINT()
|
||||
lib.jacobian_to_curve(jp, q, int2bn(curve.p))
|
||||
q = from_POINT(q)
|
||||
assert q == (p.x(), p.y())
|
||||
|
||||
|
||||
def test_cond_negate(curve, r):
|
||||
x = r.randrange(0, curve.p)
|
||||
a = int2bn(x)
|
||||
lib.conditional_negate(0, a, int2bn(curve.p))
|
||||
assert bn2int(a) == x
|
||||
lib.conditional_negate(-1, a, int2bn(curve.p))
|
||||
assert bn2int(a) == curve.p - x
|
||||
|
||||
|
||||
def test_jacobian_add(curve, r):
|
||||
p1 = r.randpoint(curve)
|
||||
p2 = r.randpoint(curve)
|
||||
prime = int2bn(curve.p)
|
||||
q = POINT()
|
||||
jp2 = JACOBIAN()
|
||||
lib.curve_to_jacobian(to_POINT(p2), jp2, prime)
|
||||
lib.point_jacobian_add(to_POINT(p1), jp2, prime)
|
||||
lib.jacobian_to_curve(jp2, q, prime)
|
||||
q = from_POINT(q)
|
||||
p_ = p1 + p2
|
||||
assert (p_.x(), p_.y()) == q
|
||||
|
||||
def test_jacobian_double(curve, r):
|
||||
p = r.randpoint(curve)
|
||||
p2 = p.double()
|
||||
prime = int2bn(curve.p)
|
||||
q = POINT()
|
||||
jp = JACOBIAN()
|
||||
lib.curve_to_jacobian(to_POINT(p), jp, prime)
|
||||
lib.point_jacobian_double(jp, curve.ptr)
|
||||
lib.jacobian_to_curve(jp, q, prime)
|
||||
q = from_POINT(q)
|
||||
assert (p2.x(), p2.y()) == q
|
||||
|
||||
def sigdecode(sig, _):
|
||||
return map(bytes2num, [sig[:32], sig[32:]])
|
||||
|
||||
|
||||
def test_sign(curve, r):
|
||||
priv = r.randbytes(32)
|
||||
digest = r.randbytes(32)
|
||||
sig = r.randbytes(64)
|
||||
|
||||
lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0))
|
||||
|
||||
exp = bytes2num(priv)
|
||||
sk = ecdsa.SigningKey.from_secret_exponent(exp, curve,
|
||||
hashfunc=hashlib.sha256)
|
||||
vk = sk.get_verifying_key()
|
||||
|
||||
sig_ref = sk.sign_digest_deterministic(digest, hashfunc=hashlib.sha256)
|
||||
assert binascii.hexlify(sig) == binascii.hexlify(sig_ref)
|
||||
|
||||
assert vk.verify_digest(sig, digest, sigdecode)
|
@ -1,3 +1,3 @@
|
||||
xpubaddrgen
|
||||
mksecptable
|
||||
mktable
|
||||
bip39bruteforce
|
||||
|
Loading…
Reference in new issue