Example #1
0
def get_subnode(node, i):
    # Public Child key derivation (CKD) algorithm of BIP32
    i_as_bytes = struct.pack(">L", i)

    if i & HARDENED_FLAG:
        raise ValueError("Prime derivation not supported")

    # Public derivation
    data = node.public_key + i_as_bytes

    I64 = hmac.HMAC(key=node.chain_code, msg=data,
                    digestmod=hashlib.sha512).digest()
    I_left_as_exponent = int.from_bytes(I64[:32], "big")

    # BIP32 magic converts old public key to new public point
    point = SEC1Encoder.decode_public_key(node.public_key, secp256k1)
    result = I_left_as_exponent * secp256k1.G + point

    if point == Point.IDENTITY_ELEMENT:
        raise ValueError("Point cannot be INFINITY")

    # Convert public point to compressed public key
    public_key = SEC1Encoder.encode_public_key(result)

    return HDNodeType(
        depth=node.depth + 1,
        child_num=i,
        chain_code=I64[32:],
        fingerprint=hash_160(node.public_key)[:4],
        public_key=public_key,
    )
Example #2
0
    def test_decode_public_key(self):
        expected_public = Point(
            x=0xE5E2C01985AAFB6E2C3AD49F3DB5CCC54B2E63343AF405B521303D0F35835062,
            y=0x3DAD76DF888ABDE5ED0CC5AF1B83968EDFFCAE5D70BEDB24FDC18BB5F79499D0,
            curve=secp256k1,
        )
        public_from_compressed = SEC1Encoder.decode_public_key(
            unhexlify(b"02e5e2c01985aafb6e2c3ad49f3db5ccc54b2e63343af405b521303d0f35835062"), secp256k1
        )
        public_from_uncompressed = SEC1Encoder.decode_public_key(
            unhexlify(
                b"04e5e2c01985aafb6e2c3ad49f3db5ccc54b2e63343af405b521303d0f3583506"
                b"23dad76df888abde5ed0cc5af1b83968edffcae5d70bedb24fdc18bb5f79499d0"
            ),
            secp256k1,
        )

        # Same values as in `test_encode_public_key`, verified using openssl
        self.assertEqual(public_from_compressed, expected_public)
        self.assertEqual(public_from_uncompressed, expected_public)
        with self.assertRaises(InvalidSEC1PublicKey) as e:
            SEC1Encoder.decode_public_key(b"\x02", secp256k1)  # invalid compressed length
        self.assertEqual(e.exception.args[0], "A compressed public key must be 33 bytes long")
        with self.assertRaises(InvalidSEC1PublicKey) as e:
            SEC1Encoder.decode_public_key(b"\x04", secp256k1)  # invalid uncompressed length
        self.assertEqual(e.exception.args[0], "An uncompressed public key must be 65 bytes long")
        with self.assertRaises(InvalidSEC1PublicKey) as e:
            # invalid prefix value
            SEC1Encoder.decode_public_key(
                unhexlify(b"05e5e2c01985aafb6e2c3ad49f3db5ccc54b2e63343af405b521303d0f35835062"), secp256k1
            )
        self.assertEqual(e.exception.args[0], "Wrong key format")

        # With P256, same values as in `test_encode_public_key`, verified using openssl
        expected_P256 = Point(
            x=0x12C9DDF64B0D1F1D91D9BD729ABFB880079FA889D66604CC0B78C9CBC271824C,
            y=0x9A7D581BCF2ABA680B53CEDBADE03BE62FE95869DA04A168A458F369AC6A823E,
            curve=P256,
        )
        public_from_compressed = SEC1Encoder.decode_public_key(
            unhexlify(b"0212c9ddf64b0d1f1d91d9bd729abfb880079fa889d66604cc0b78c9cbc271824c"), P256
        )
        self.assertEqual(public_from_compressed, expected_P256)

        # With secp192k1, same values as in `test_encode_public_key`, verified using openssl
        expected_secp192k1 = Point(
            x=0xA3BEC5FBA6D13E51FB55BD88DD097CB9B04F827BC151D22D,
            y=0xF07A73819149E8D903AA983E52AB1CFF38F0D381F940D361,
            curve=secp192k1,
        )
        public_from_compressed = SEC1Encoder.decode_public_key(
            unhexlify(b"03a3bec5fba6d13e51fb55bd88dd097cb9b04f827bc151d22d"), secp192k1
        )
        self.assertEqual(public_from_compressed, expected_secp192k1)
Example #3
0
    def derive_revoke_keys(self, per_commitment_point, per_commitment_secret, revocation_basepoint, revocation_basepoint_secret):
        # revocationpubkey = revocation_basepoint * SHA256(revocation_basepoint || per_commitment_point) +
        #                     per_commitment_point * SHA256(per_commitment_point || revocation_basepoint)
        hash1 = hashlib.sha256()
        hash1.update(convert_to_bytes(revocation_basepoint))
        hash1.update(convert_to_bytes(per_commitment_point))

        rev_digest1 = hash1.digest()
        int_rev_digest1 = int.from_bytes(rev_digest1, byteorder='big')

        #print("rev_digest1 => ", rev_digest1.hex())
        #print("int_rev_digest1 => ", int_rev_digest1)

        # revocation_basepoint * rev_digest1
        R1 = revocation_basepoint * int_rev_digest1

        if self.verbose: print("R1 => ", SEC1Encoder.encode_public_key(R1).hex())

        hash2 = hashlib.sha256()
        hash2.update(convert_to_bytes(per_commitment_point))
        hash2.update(convert_to_bytes(revocation_basepoint))

        rev_digest2 = hash2.digest()
        int_rev_digest2 = int.from_bytes(rev_digest2, byteorder='big')

        # per_commitment_point * rev_digest2
        R2 = per_commitment_point * int_rev_digest2

        if self.verbose: print("R2 => ", SEC1Encoder.encode_public_key(R2).hex())

        rev_pubkey = R1 + R2
        if self.verbose: print("revocation_pubkey: 0x%s" % convert_to_bytes(rev_pubkey).hex())
        rev_pubkey_hex = convert_to_bytes(rev_pubkey).hex()

        # revocationprivkey = revocation_basepoint_secret * SHA256(revocation_basepoint || per_commitment_point) +
        #                      per_commitment_secret * SHA256(per_commitment_point || revocation_basepoint)

        R3 = (revocation_basepoint_secret * int_rev_digest1) % curve.secp256k1.q
        if self.verbose: print("R3 => ", hex(R3))

        R4 = (per_commitment_secret * int_rev_digest2) % curve.secp256k1.q
        if self.verbose: print("R4 => ", hex(R4))

        rev_privkey = (R3 + R4) % curve.secp256k1.q
        if self.verbose: print("revocation_privkey: %s" % hex(rev_privkey))
        rev_privkey_hex = hex(rev_privkey).lstrip("0x")

        return rev_pubkey_hex, rev_privkey_hex
Example #4
0
    def _derive_private_key(self, seed_pri, cred_id, rp_id):
        alg = cred_id[0]
        if alg != 0:
            raise UnknownKeyAgreementScheme(alg)

        eph_pub_enc = cred_id[1:][:65]
        eph_pub = SEC1Encoder.decode_public_key(eph_pub_enc, P256)

        ecdh_point = seed_pri * eph_pub
        ikm_x = fastecdsa.encoding.util.int_to_bytes(ecdh_point.x)
        cred_key = hkdf(ikm_x, binascii.a2b_hex('776562617574686e2e7265636f766572792e637265645f6b6579'), length=32)
        cred_key_int = int.from_bytes(cred_key, 'big', signed=False)

        mac_key = hkdf(ikm_x, binascii.a2b_hex('776562617574686e2e7265636f766572792e6d61635f6b6579'), length=32)
        full_mac = hmac(mac_key,
                        struct.pack('>B65s32s',
                                    alg,
                                    eph_pub_enc,
                                    sha256(rp_id.encode('utf-8'))))
        mac = full_mac[0:16]

        recon_cred_id = struct.pack('>B65s16s', alg, eph_pub_enc, mac)
        if cred_id != recon_cred_id:
            raise RpIdMismatch()

        assert cred_key_int < N, "cred_key >= N: " + str(cred_key_int)

        cred_pri = cred_key_int + seed_pri % N
        return cred_pri
Example #5
0
    def from_secret_key(cls, secret_key: bytes, curve=b'ed'):
        """
        Creates a key object from a secret exponent.
        :param secret_key: secret exponent or seed
        :param curve: an elliptic curve used, default is ed25519
        """
        # Ed25519
        if curve == b'ed':
            # Dealing with secret key or seed?
            if len(secret_key) == 64:
                public_key = pysodium.crypto_sign_sk_to_pk(sk=secret_key)
            else:
                public_key, secret_key = pysodium.crypto_sign_seed_keypair(seed=secret_key)
        # Secp256k1
        elif curve == b'sp':
            sk = secp256k1.PrivateKey(secret_key)
            public_key = sk.pubkey.serialize()
        # P256
        elif curve == b'p2':
            pk = get_public_key(bytes_to_int(secret_key), curve=P256)
            public_key = SEC1Encoder.encode_public_key(pk)
        else:
            assert False

        return cls(public_key, secret_key, curve=curve)
Example #6
0
    def from_secret_exponent(cls,
                             secret_exponent: bytes,
                             curve=b'ed',
                             activation_code=None):
        """
        Creates a key object from a secret exponent.
        :param secret_exponent: secret exponent or seed
        :param curve: b'sp' for Secp251k1, b'p2' for P256/Secp256r1, b'ed' for Ed25519 (default)
        :param activation_code: secret for initializing account balance
        """
        # Ed25519
        if curve == b'ed':
            # Dealing with secret exponent or seed?
            if len(secret_exponent) == 64:
                public_point = pysodium.crypto_sign_sk_to_pk(
                    sk=secret_exponent)
            else:
                public_point, secret_exponent = pysodium.crypto_sign_seed_keypair(
                    seed=secret_exponent)
        # Secp256k1
        elif curve == b'sp':
            sk = secp256k1.PrivateKey(secret_exponent)
            public_point = sk.pubkey.serialize()
        # P256
        elif curve == b'p2':
            pk = get_public_key(bytes_to_int(secret_exponent), curve=P256)
            public_point = SEC1Encoder.encode_public_key(pk)
        else:
            assert False

        return cls(public_point,
                   secret_exponent,
                   curve=curve,
                   activation_code=activation_code)
Example #7
0
def did_callback_elaphant(request):
    if request.method == 'POST':
        response = json.loads(request.body)
        if request.content_type == "application/json" or 'Data' not in response.keys(
        ):
            HttpResponse(status=400)
        data = json.loads(response['Data'])
        sig = response['Sign']
        client_public_key = data['PublicKey']

        r, s = int(sig[:64], 16), int(sig[64:], 16)
        public_key = SEC1Encoder.decode_public_key(
            unhexlify(client_public_key), curve.P256)
        valid = ecdsa.verify((r, s), response['Data'], public_key)
        if not valid:
            return JsonResponse({'message': 'Unauthorized'}, status=401)

        try:
            recently_created_time = timezone.now() - timedelta(minutes=1)
            did_request_query_result = DIDRequest.objects.get(
                state=data["RandomNumber"],
                created_at__gte=recently_created_time)
            if not did_request_query_result:
                return JsonResponse({'message': 'Unauthorized'}, status=401)
            data["auth"] = True
            DIDRequest.objects.filter(state=data["RandomNumber"]).update(
                data=json.dumps(data))
        except Exception as e:
            logging.debug(f"Method: did_callback_elaphant Error: {e}")
            return JsonResponse({'error': str(e)}, status=404)

    return JsonResponse({'result': True}, status=200)
Example #8
0
 def derive_pubkey(self, secret):
     P = keys.get_public_key(secret, curve.secp256k1)
     pub_key = SEC1Encoder.encode_public_key(P)
     #print("Pub key: ", pub_key)
     #print("pubkey : ", hexlify(pub_key))
     # return hex encoding in bytes AND int encoding
     return hexlify(pub_key), P
Example #9
0
 def check_signature(self):
     if self._from == NULL_BYTE:
         return True
     if not self.is_signed():
         return False
     to_sign = self.calculate_hash()
     return ecdsa.verify(
         self._signature, to_sign,
         SEC1Encoder.decode_public_key(self._from, curve=curve.P256))
Example #10
0
def private_key_to_public_key(private_key):
    """
	Accept a hex private key and convert it to its respective public key. 
	Because converting a private key to a public key requires SECP256k1 ECDSA 
	signing, this function is the most time consuming and is a bottleneck in 
	the overall speed of the program.
	Average Time: 0.0031567731 seconds
	"""
    #pk = PrivateKey().fromString(bytes.fromhex(private_key))
    pk2 = binascii.hexlify(
        SEC1Encoder.encode_public_key(secp256k1.G * int(private_key, 16),
                                      compressed=False))
    #print('pubstark 04' + pk.publicKey().toString().hex().upper())
    #print('pubfast  ' + pk2.decode('utf-8').upper())
    #return '04' + pk.publicKey().toString().hex().upper()
    return (pk2.decode('utf-8').upper())
Example #11
0
    def _test_runner(self, tests, curve, hashfunc):
        for test_group in tests:
            keybytes = unhexlify(test_group["key"]["uncompressed"])
            public_key = SEC1Encoder.decode_public_key(keybytes, curve)

            for test in test_group["tests"]:
                try:
                    message = unhexlify(test["msg"])
                    sigbytes = unhexlify(test["sig"])
                    signature = DEREncoder.decode_signature(sigbytes)
                    expected = test["result"] == "valid"

                    result = verify(signature, message, public_key, curve, hashfunc)
                    self.assertEqual(result, expected, test)
                except:
                    self.assertFalse(test["result"] == "valid", test)
Example #12
0
    def import_recovery_seed(self, exported_seed):
        payload = cbor.decode(exported_seed)
        alg = payload[1]
        aaguid = payload[3]
        sig = payload[4]

        assert isinstance(alg, int)
        assert isinstance(aaguid, bytes)
        assert isinstance(sig, bytes)

        if alg == 0:
            S_enc = payload[-1]
            assert isinstance(S_enc, bytes)
            S = SEC1Encoder().decode_public_key(S_enc, P256)

            self._seeds.append(BackupSeed(alg, aaguid, S))

        else:
            raise UnknownKeyAgreementScheme(alg)

        self._state += 1
def did_callback():
    if request.method == 'POST':
        if not request.json or not 'Data' in request.json:
            abort(400)
        data = request.json['Data']
        data_json = json.loads(data)
        sig = request.json['Sign']
        client_public_key = data_json['PublicKey']

        r, s = int(sig[:64], 16), int(sig[64:], 16)
        public_key = SEC1Encoder.decode_public_key(
            unhexlify(client_public_key), curve.P256)
        valid = ecdsa.verify((r, s), data, public_key)
        if not valid:
            return jsonify({'message': 'Unauthorized'}), 401
        try:
            c, conn = connection()
            x = c.execute(
                "SELECT data FROM didauth_requests WHERE state = %s AND created_at >= (NOW() - INTERVAL 1 MINUTE)",
                [thwart(data_json["RandomNumber"])])
            if int(x) == 0:
                return jsonify({'message': 'Unauthorized'}), 401
            auth_data = json.loads(c.fetchone()[0])
            auth_data["auth"] = True
            auth_data = {
                key: value
                for (key, value) in (auth_data.items() + data_json.items())
            }

            c.execute("UPDATE didauth_requests SET data = %s WHERE state = %s",
                      (json.dumps(auth_data), data_json["RandomNumber"]))
            conn.commit()
        except Exception as e:
            return (str(e))
        finally:
            if (conn):
                c.close()
                conn.close()
                gc.collect()
    return jsonify({'result': True}), 201
Example #14
0
    def verify(self, signature, message):
        """
        Verify signature, raise exception if it is not valid
        :param message: sequance of bytes, raw format or hexadecimal notation
        :param signature: a signature in base58 encoding
        """
        signature = scrub_input(signature)
        message = scrub_input(message)

        if not self.public_point:
            raise ValueError("Cannot verify without a public key")

        if signature[:3] != b'sig':  # not generic
            if self.curve != signature[:2]:  # "sp", "p2" "ed"
                raise ValueError("Signature and public key curves mismatch.")

        signature = base58_decode(signature)

        # Ed25519
        if self.curve == b"ed":
            digest = pysodium.crypto_generichash(message)
            try:
                pysodium.crypto_sign_verify_detached(signature, digest,
                                                     self.public_point)
            except ValueError:
                raise ValueError('Signature is invalid.')
        # Secp256k1
        elif self.curve == b"sp":
            pk = secp256k1.PublicKey(self.public_point, raw=True)
            sig = pk.ecdsa_deserialize_compact(signature)
            if not pk.ecdsa_verify(message, sig, digest=blake2b_32):
                raise ValueError('Signature is invalid.')
        # P256
        elif self.curve == b"p2":
            pk = SEC1Encoder.decode_public_key(self.public_point, curve=P256)
            r, s = bytes_to_int(signature[:32]), bytes_to_int(signature[32:])
            if not verify(sig=(r, s), msg=message, Q=pk, hashfunc=blake2b_32):
                raise ValueError('Signature is invalid.')
        else:
            assert False
Example #15
0
    def test_encode_public_key(self):
        # 1/ PrivateKey generated using openssl "openssl ecparam -name secp256k1 -genkey -out ec-priv.pem"
        # 2/ Printed using "openssl ec -in ec-priv.pem -text -noout" and converted to numeric using "asn1._bytes_to_int"
        priv_key = 7002880736699640265110069622773736733141182416793484574964618597954446769264
        pubkey_compressed = hexlify(SEC1Encoder.encode_public_key(secp256k1.G * priv_key))
        pubkey_uncompressed = hexlify(SEC1Encoder.encode_public_key(secp256k1.G * priv_key, compressed=False))

        # 3/ PublicKey extracted using "openssl ec -in ec-priv.pem -pubout -out ec-pub.pem"
        # 4/ Encoding verified using openssl "openssl ec -in ec-pub.pem -pubin -text -noout -conv_form compressed"
        self.assertEqual(pubkey_compressed, b"02e5e2c01985aafb6e2c3ad49f3db5ccc54b2e63343af405b521303d0f35835062")
        self.assertEqual(
            pubkey_uncompressed,
            b"04e5e2c01985aafb6e2c3ad49f3db5ccc54b2e63343af405b521303d0f3583506"
            b"23dad76df888abde5ed0cc5af1b83968edffcae5d70bedb24fdc18bb5f79499d0",
        )

        # Same with P256 Curve
        priv_P256 = 807015861248675637760562792774171551137308512372870683367415858378856470633
        pubkey_compressed = hexlify(SEC1Encoder.encode_public_key(P256.G * priv_P256))
        pubkey_uncompressed = hexlify(SEC1Encoder.encode_public_key(P256.G * priv_P256, compressed=False))
        self.assertEqual(pubkey_compressed, b"0212c9ddf64b0d1f1d91d9bd729abfb880079fa889d66604cc0b78c9cbc271824c")
        self.assertEqual(
            pubkey_uncompressed,
            b"0412c9ddf64b0d1f1d91d9bd729abfb880079fa889d66604cc0b78c9cbc271824"
            b"c9a7d581bcf2aba680b53cedbade03be62fe95869da04a168a458f369ac6a823e",
        )

        # And secp192k1 Curve
        priv_secp192k1 = 5345863567856687638748079156318679969014620278806295592453
        pubkey_compressed = hexlify(SEC1Encoder.encode_public_key(secp192k1.G * priv_secp192k1))
        pubkey_uncompressed = hexlify(SEC1Encoder.encode_public_key(secp192k1.G * priv_secp192k1, compressed=False))
        self.assertEqual(pubkey_compressed, b"03a3bec5fba6d13e51fb55bd88dd097cb9b04f827bc151d22d")
        self.assertEqual(
            pubkey_uncompressed,
            b"04a3bec5fba6d13e51fb55bd88dd097cb9b04f827bc151d22df07a73819149e8d903aa983e52ab1cff38f0d381f940d361",
        )
Example #16
0
#*  See the License for the specific language governing permissions and
#*  limitations under the License.
#********************************************************************************
from ledgerblue.comm import getDongle
from ledgerblue.commException import CommException
from secp256k1 import PublicKey
import bitcoin
import struct
from fastecdsa.encoding.sec1 import SEC1Encoder
from fastecdsa import curve

bipp44_path = ("8000002C" + "80000378" + "80000000" + "00000000" + "00000000")

b = bytes.fromhex(
    "037edf1d72c29e6de321e95d1d0c2736223fe895009bf448e520c1333b05d6d6fd")
p = SEC1Encoder.decode_public_key(b, curve=curve.P256)
p2 = SEC1Encoder.encode_public_key(p, compressed=False).hex()

payload = bytes.fromhex(p2 + bipp44_path)

ecdhPayloadArray = [payload]

dongle = getDongle(True)
publicKey = dongle.exchange(bytes.fromhex("80040000FF" + bipp44_path))
print("got publicKey " + publicKey.hex())
print("compressed: " + bitcoin.compress(publicKey).hex())
print("requesting ecdh with: " + p2)

for ecdhPayload in ecdhPayloadArray:
    try:
        offset = 0
Example #17
0
 def from_bytes(cls, data: bytes, curve: str) -> "ECCPublicKey":
     curve_type = infer_local_type(curve)
     public_key_impl = SEC1Encoder.decode_public_key(data, curve_type)
     return cls(public_key_impl, curve_type)
Example #18
0
 def to_bytes(self) -> bytes:
     return SEC1Encoder.encode_public_key(self.impl, compressed=False)
Example #19
0
def encode_pub(pubkey):
    return SEC1Encoder().encode_public_key(pubkey, compressed=False)
Example #20
0
def cose_key_to_point(cose):
    return SEC1Encoder.decode_public_key(
        b'\x04' + cose[-2] + cose[-3],
        P256
    )
Example #21
0
def convert_to_bytes(point):
    return SEC1Encoder.encode_public_key(point)
Example #22
0
def convert_to_int(point):
    _point = SEC1Encoder.encode_public_key(point)
    return int.from_bytes(_point, byteorder='big')