# ===================================================================
#
# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from __future__ import print_function
import re
import sys
import struct
import binascii
from collections import namedtuple
from Cryptodome.Util.py3compat import bord, tobytes, tostr, bchr, is_string
from Cryptodome.Util.number import bytes_to_long, long_to_bytes
from Cryptodome.Math.Numbers import Integer
from Cryptodome.Util.asn1 import (DerObjectId, DerOctetString, DerSequence,
DerBitString)
from Cryptodome.PublicKey import (_expand_subject_public_key_info,
_create_subject_public_key_info,
_extract_subject_public_key_info)
from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer,
SmartPointer, c_size_t, c_uint8_ptr,
c_ulonglong)
from Cryptodome.Random import get_random_bytes
from Cryptodome.Random.random import getrandbits
_ec_lib = load_pycryptodome_raw_lib("Cryptodome.PublicKey._ec_ws", """
typedef void EcContext;
typedef void EcPoint;
int ec_ws_new_context(EcContext **pec_ctx,
const uint8_t *modulus,
const uint8_t *b,
const uint8_t *order,
size_t len,
uint64_t seed);
void ec_free_context(EcContext *ec_ctx);
int ec_ws_new_point(EcPoint **pecp,
const uint8_t *x,
const uint8_t *y,
size_t len,
const EcContext *ec_ctx);
void ec_free_point(EcPoint *ecp);
int ec_ws_get_xy(uint8_t *x,
uint8_t *y,
size_t len,
const EcPoint *ecp);
int ec_ws_double(EcPoint *p);
int ec_ws_add(EcPoint *ecpa, EcPoint *ecpb);
int ec_ws_scalar(EcPoint *ecp,
const uint8_t *k,
size_t len,
uint64_t seed);
int ec_ws_clone(EcPoint **pecp2, const EcPoint *ecp);
int ec_ws_copy(EcPoint *ecp1, const EcPoint *ecp2);
int ec_ws_cmp(const EcPoint *ecp1, const EcPoint *ecp2);
int ec_ws_neg(EcPoint *p);
int ec_ws_normalize(EcPoint *ecp);
int ec_ws_is_pai(EcPoint *ecp);
""")
_Curve = namedtuple("_Curve", "p b order Gx Gy G modulus_bits oid context desc openssh")
_curves = {}
p256_names = ["p256", "NIST P-256", "P-256", "prime256v1", "secp256r1",
"nistp256"]
def init_p256():
p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
order = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
p256_modulus = long_to_bytes(p, 32)
p256_b = long_to_bytes(b, 32)
p256_order = long_to_bytes(order, 32)
ec_p256_context = VoidPointer()
result = _ec_lib.ec_ws_new_context(ec_p256_context.address_of(),
c_uint8_ptr(p256_modulus),
c_uint8_ptr(p256_b),
c_uint8_ptr(p256_order),
c_size_t(len(p256_modulus)),
c_ulonglong(getrandbits(64))
)
if result:
raise ImportError("Error %d initializing P-256 context" % result)
context = SmartPointer(ec_p256_context.get(), _ec_lib.ec_free_context)
p256 = _Curve(Integer(p),
Integer(b),
Integer(order),
Integer(Gx),
Integer(Gy),
None,
256,
"1.2.840.10045.3.1.7", # ANSI X9.62
context,
"NIST P-256",
"ecdsa-sha2-nistp256")
global p256_names
_curves.update(dict.fromkeys(p256_names, p256))
init_p256()
del init_p256
p384_names = ["p384", "NIST P-384", "P-384", "prime384v1", "secp384r1",
"nistp384"]
def init_p384():
p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff
b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef
order = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973
Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7
Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F
p384_modulus = long_to_bytes(p, 48)
p384_b = long_to_bytes(b, 48)
p384_order = long_to_bytes(order, 48)
ec_p384_context = VoidPointer()
result = _ec_lib.ec_ws_new_context(ec_p384_context.address_of(),
c_uint8_ptr(p384_modulus),
c_uint8_ptr(p384_b),
c_uint8_ptr(p384_order),
c_size_t(len(p384_modulus)),
c_ulonglong(getrandbits(64))
)
if result:
raise ImportError("Error %d initializing P-384 context" % result)
context = SmartPointer(ec_p384_context.get(), _ec_lib.ec_free_context)
p384 = _Curve(Integer(p),
Integer(b),
Integer(order),
Integer(Gx),
Integer(Gy),
None,
384,
"1.3.132.0.34", # SEC 2
context,
"NIST P-384",
"ecdsa-sha2-nistp384")
global p384_names
_curves.update(dict.fromkeys(p384_names, p384))
init_p384()
del init_p384
p521_names = ["p521", "NIST P-521", "P-521", "prime521v1", "secp521r1",