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
|
from .math import Math
from .utils.integer import RandomInteger
from .utils.pem import getPemContent, createPem
from .utils.binary import hexFromByteString, byteStringFromHex, intFromHex, base64FromByteString, byteStringFromBase64
from .utils.der import hexFromInt, parse, encodeConstructed, DerFieldType, encodePrimitive
from .curve import secp256k1, getByOid
from .publicKey import PublicKey
class PrivateKey:
def __init__(self, curve=secp256k1, secret=None):
self.curve = curve
self.secret = secret or RandomInteger.between(1, curve.N - 1)
def publicKey(self):
curve = self.curve
publicPoint = Math.multiply(
p=curve.G,
n=self.secret,
N=curve.N,
A=curve.A,
P=curve.P,
)
return PublicKey(point=publicPoint, curve=curve)
def toString(self):
return hexFromInt(self.secret)
def toDer(self):
publicKeyString = self.publicKey().toString(encoded=True)
hexadecimal = encodeConstructed(
encodePrimitive(DerFieldType.integer, 1),
encodePrimitive(DerFieldType.octetString, hexFromInt(self.secret)),
encodePrimitive(DerFieldType.oidContainer, encodePrimitive(DerFieldType.object, self.curve.oid)),
encodePrimitive(DerFieldType.publicKeyPointContainer, encodePrimitive(DerFieldType.bitString, publicKeyString))
)
return byteStringFromHex(hexadecimal)
def toPem(self):
der = self.toDer()
return createPem(content=base64FromByteString(der), template=_pemTemplate)
@classmethod
def fromPem(cls, string):
privateKeyPem = getPemContent(pem=string, template=_pemTemplate)
return cls.fromDer(byteStringFromBase64(privateKeyPem))
@classmethod
def fromDer(cls, string):
hexadecimal = hexFromByteString(string)
privateKeyFlag, secretHex, curveData, publicKeyString = parse(hexadecimal)[0]
if privateKeyFlag != 1:
raise Exception("Private keys should start with a '1' flag, but a '{flag}' was found instead".format(
flag=privateKeyFlag
))
curve = getByOid(curveData[0])
privateKey = cls.fromString(string=secretHex, curve=curve)
if privateKey.publicKey().toString(encoded=True) != publicKeyString[0]:
raise Exception("The public key described inside the private key file doesn't match the actual public key of the pair")
return privateKey
@classmethod
def fromString(cls, string, curve=secp256k1):
return PrivateKey(secret=intFromHex(string), curve=curve)
_pemTemplate = """
-----BEGIN EC PRIVATE KEY-----
{content}
-----END EC PRIVATE KEY-----
"""
|