[Cryptech-Commits] [sw/libhal] 01/14: Snapshot PKCS #8 Python hacks.

git at cryptech.is git at cryptech.is
Thu Apr 6 23:38:00 UTC 2017


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch pkcs8
in repository sw/libhal.

commit 6e3faad9418e66b2d02e8857c3449ce3e5f93e78
Author: Rob Austein <sra at hactrn.net>
AuthorDate: Tue Mar 28 21:34:15 2017 -0500

    Snapshot PKCS #8 Python hacks.
    
    This will almost certainly merge into test scripts or libhal.py at
    some later date, right now just get it into git for archive.
---
 pkcs8.py | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 280 insertions(+)

diff --git a/pkcs8.py b/pkcs8.py
new file mode 100644
index 0000000..cbd5c27
--- /dev/null
+++ b/pkcs8.py
@@ -0,0 +1,280 @@
+# Temporary sandbox for Python PKCS #8 hacks, probably integrate into
+# test scripts, libhal.py, etc once have figured this out.
+#
+# Both PyCrpto and the Python ecdsa package have their own ASN.1, so
+# why are we using yet another package?  Because it's easier to
+# understand, that's why.  Perhaps once we've debugged this we'll
+# recode it using one of the other packages to reduce external
+# dependencies, but for now, pyasn1 wins on ease of debugging.
+#
+# Also see the "native" encode and decode routines in pyasn1, which
+# supposedly encode and decode to built-in Python data types instead
+# of the fancy types from the pyasn1 library.  Might be simpler, but
+# whole new mess so defer for now.
+
+# RFC 5208: PKCS #8
+# RFC 2313: PKCS #1.5 [rsa.c]
+# RFC 5915: EC keys   [ecdsa.c]
+
+from pyasn1.type.univ           import Sequence, SetOf, Integer, OctetString, ObjectIdentifier, BitString, Any
+from pyasn1.type.namedtype      import NamedTypes, NamedType, OptionalNamedType
+from pyasn1.type.namedval       import NamedValues
+from pyasn1.type.tag            import Tag, tagClassContext, tagFormatSimple, tagFormatConstructed
+from pyasn1.type.constraint     import SingleValueConstraint
+from pyasn1.codec.der.encoder   import encode as DER_Encode
+from pyasn1.codec.der.decoder   import decode as DER_Decode
+
+class AlgorithmIdentifier(Sequence):
+    componentType = NamedTypes(
+        NamedType(              "algorithm",            ObjectIdentifier()),
+        OptionalNamedType(      "parameters",           Any()))
+
+class AttributeTypeAndValue(Sequence):
+    componentType = NamedTypes(
+        NamedType(              "type",                 ObjectIdentifier()),
+        NamedType(              "value",                Any()))
+
+class Attribute(Sequence):
+    componentType = NamedTypes(
+        NamedType(              "type",                 ObjectIdentifier()),
+        NamedType(              "vals",                 SetOf(componentType = Any())))
+
+# RFC 5208
+
+class PrivateKeyInfo(Sequence):
+    componentType = NamedTypes(
+        NamedType(              "version",              Integer(namedValues = NamedValues(("v1", 0)))                   .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(0))),
+        NamedType(              "privateKeyAlgorithm",  AlgorithmIdentifier()),
+        NamedType(              "privateKey",           OctetString()),
+        OptionalNamedType(      "attributes",           SetOf(componentType = Attribute())                              .subtype(implicitTag = Tag(tagClassContext, tagFormatConstructed, 0))))
+
+class EncryptedPrivateKeyInfo(Sequence):
+    componentType = NamedTypes(
+        NamedType(              "encryptionAlgorithm",  AlgorithmIdentifier()),
+        NamedType(              "encryptedData",        OctetString()))
+
+# RFC 2313
+
+class RSAPrivateKey(Sequence):
+    componentType = NamedTypes(
+        NamedType(              "version",              Integer()                                                       .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(0))),
+        NamedType(              "n",                    Integer()),
+        NamedType(              "e",                    Integer()),
+        NamedType(              "d",                    Integer()),
+        NamedType(              "p",                    Integer()),
+        NamedType(              "q",                    Integer()),
+        NamedType(              "dP",                   Integer()),
+        NamedType(              "dQ",                   Integer()),
+        NamedType(              "u",                    Integer()))
+
+# RFC 5915
+
+class ECPrivateKey(Sequence):
+    componentType = NamedTypes(
+        NamedType(              "version",              Integer(namedValues = NamedValues(("ecPrivkeyVer1", 1)))        .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(1))),
+        NamedType(              "privateKey",           OctetString()),
+        OptionalNamedType(      "parameters",           ObjectIdentifier()                                              .subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 0))),
+        OptionalNamedType(      "publicKey",            BitString()                                                     .subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 1))))
+
+# Test data, generated by OpenSSL
+
+der_test_keys = dict(
+
+    ec_rfc5915 = '''
+        MHcCAQEEIFWaZOsQxLwZmIK4YAuf1d8S9Pnznvzcl9TjiMpvXkCYoAoGCCqGSM49
+        AwEHoUQDQgAEC/8vH5bL+3KNNF/NL+VmUKZQtjA59UsGtKP6FP4ZqFc3Y7Gie77/
+        lG1/L+s/6ircB1JkI8zaE3KYd7s+7IYIEQ==
+    '''.decode("base64"),
+
+    ec_pkcs8 = '''
+        MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVZpk6xDEvBmYgrhg
+        C5/V3xL0+fOe/NyX1OOIym9eQJihRANCAAQL/y8flsv7co00X80v5WZQplC2MDn1
+        Swa0o/oU/hmoVzdjsaJ7vv+UbX8v6z/qKtwHUmQjzNoTcph3uz7shggR
+    '''.decode("base64"),
+
+    rsa_rfc2313 = '''
+        MIIEpAIBAAKCAQEAx/N9ee3u6Z6qjw5waPhuUBYy7m6+kRfNYB8KSERGd5K2xD96
+        IeyvEv+xMDA2BQ3xOummL2yAjtMZ2N7Le37nfpvtzwVWqrOHzq7OWaw/pPl1N9Lq
+        VSQLPoxHw3TVe69QNPVu5SeumaOGXmzTIs1pr2yVBZD/i2KYiif3BO2SgoDx7g4s
+        cFdg/6YiDpKYbY/yx4YN6KJxDGMM6DE0Ih8hE68flJMSIbUWIaJZo0b7XPeE9zYU
+        zf93VLvuYIqWYMuwTw5TSUnzeRq6ALJpf90nObduJsYEPu/i4RFlxdm5WsmOb2Tu
+        F7JFesEdGeT9lCxxd3CI5YTItQIBWsx0AzCS/QIDAQABAoIBAQCmC7Zvwv9cUr8g
+        /cSr52L0bvrstlra8wFCiYRobwp10gilAHHUKlFZXa0vb1ns6J8jZVT0nQ5FjVkx
+        mBMzAzgLFEJwYOaP63ckVFZYcYqI3gBR0312JvCPiL8vuZ5vkC7zS75D3qhIPlwf
+        ng/YHu1dGLbIYJlWjxJN6NJh7Uh1xlZcm0WAJYhJpmMIZJv2abTS4GXw4SVOyMnd
+        tPEgEfrK/y2PsNUPwnby6LR1cE2rxOQtb6gNCov0AAiE0BsJeE7jXa2IEl6lKoBR
+        ChDMAeU53pJPlcYt7ZmAgyezuEfnr4kY5Rk/nTcwTxTpzQi7Dcth8QCRqfu4wXXj
+        QEN7b9cBAoGBAPNjRPc/Z89jYp1IDR+R5oi7YTsLzNAIlS/t9wgrujnVdsm00xos
+        dd+NwvjTi7wE0fV+7u5/W9ni3077JaBGBa9+nD0iB0PgAJW+tb8HUJXABQKoTA4m
+        yyiAHNHgarwc1uwr+yAYqvSj7aAvIcZeXgi3qxDXEOSKuk8n57/TpPMVAoGBANJP
+        /9/6zxd3PdogiP0nC+piJHstexk+l4WRqGWWuRG0VTIEfBk4dQfj/UwfmTcCQxAe
+        D0e9EoHeVOfsv4nfOfDhGC7jHLkLpNJbc5ttgr2sZ6qIouBJ8suMDte/zZze27aU
+        7epFqw0w9Y58fwRyP2u5ILYFcm+cWeplg9lY4rpJAoGBALzLs1Krn4YzDOr+Whe0
+        IITN/XVFCQIStk8wo2B2MwXrvTJoDx0Ngf4AxE4qIwmdH5T0erkMmB5jK1/j12MF
+        DiH874tIWyRenXWLMwZU0UDoa7qM/Do6A3uOLUzsbT8wi9M1pp5WJD6S7qBED0oG
+        J6FRf+QXQCZYKn9+b/nQXfKlAoGADwFuPEjk5cO4Qgv4OjfC/eIqwC8qjU6N+RW/
+        ciAi7ER1n6/6OsJwdzOpKvlGMUqUBl5esLuoymNWo4Wc1PV8aNdmplHGBt3x0KB9
+        yyUxIt9eNiixllcwX52KoZIp1XuBKbHOl9yIq9RGcPgpB+Qu6jy3PMV+uL/rGnJL
+        ygIxiyECgYAwSLLuxHKGcy+oZo1vxSQlY2gOkprqK9VwjAhxGuGlJftXrL/Dkbxs
+        GatW0bGAyQ+VPivPl8YYhs34NCA1t1pJKczcNbHEJFN57x6AtCbHFLWB91wY96yA
+        6y/Bgd45PoXryQl7+GdOAPyEYY3mq3R5vaozTraPrnD+61kpKVLJ/Q==
+    '''.decode("base64"),
+
+    rsa_pkcs8 = '''
+        MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDH83157e7pnqqP
+        DnBo+G5QFjLubr6RF81gHwpIREZ3krbEP3oh7K8S/7EwMDYFDfE66aYvbICO0xnY
+        3st7fud+m+3PBVaqs4fOrs5ZrD+k+XU30upVJAs+jEfDdNV7r1A09W7lJ66Zo4Ze
+        bNMizWmvbJUFkP+LYpiKJ/cE7ZKCgPHuDixwV2D/piIOkphtj/LHhg3oonEMYwzo
+        MTQiHyETrx+UkxIhtRYholmjRvtc94T3NhTN/3dUu+5gipZgy7BPDlNJSfN5GroA
+        sml/3Sc5t24mxgQ+7+LhEWXF2blayY5vZO4XskV6wR0Z5P2ULHF3cIjlhMi1AgFa
+        zHQDMJL9AgMBAAECggEBAKYLtm/C/1xSvyD9xKvnYvRu+uy2WtrzAUKJhGhvCnXS
+        CKUAcdQqUVldrS9vWezonyNlVPSdDkWNWTGYEzMDOAsUQnBg5o/rdyRUVlhxioje
+        AFHTfXYm8I+Ivy+5nm+QLvNLvkPeqEg+XB+eD9ge7V0YtshgmVaPEk3o0mHtSHXG
+        VlybRYAliEmmYwhkm/ZptNLgZfDhJU7Iyd208SAR+sr/LY+w1Q/CdvLotHVwTavE
+        5C1vqA0Ki/QACITQGwl4TuNdrYgSXqUqgFEKEMwB5Tnekk+Vxi3tmYCDJ7O4R+ev
+        iRjlGT+dNzBPFOnNCLsNy2HxAJGp+7jBdeNAQ3tv1wECgYEA82NE9z9nz2NinUgN
+        H5HmiLthOwvM0AiVL+33CCu6OdV2ybTTGix1343C+NOLvATR9X7u7n9b2eLfTvsl
+        oEYFr36cPSIHQ+AAlb61vwdQlcAFAqhMDibLKIAc0eBqvBzW7Cv7IBiq9KPtoC8h
+        xl5eCLerENcQ5Iq6Tyfnv9Ok8xUCgYEA0k//3/rPF3c92iCI/ScL6mIkey17GT6X
+        hZGoZZa5EbRVMgR8GTh1B+P9TB+ZNwJDEB4PR70Sgd5U5+y/id858OEYLuMcuQuk
+        0ltzm22Cvaxnqoii4Enyy4wO17/NnN7btpTt6kWrDTD1jnx/BHI/a7kgtgVyb5xZ
+        6mWD2VjiukkCgYEAvMuzUqufhjMM6v5aF7QghM39dUUJAhK2TzCjYHYzBeu9MmgP
+        HQ2B/gDETiojCZ0flPR6uQyYHmMrX+PXYwUOIfzvi0hbJF6ddYszBlTRQOhruoz8
+        OjoDe44tTOxtPzCL0zWmnlYkPpLuoEQPSgYnoVF/5BdAJlgqf35v+dBd8qUCgYAP
+        AW48SOTlw7hCC/g6N8L94irALyqNTo35Fb9yICLsRHWfr/o6wnB3M6kq+UYxSpQG
+        Xl6wu6jKY1ajhZzU9Xxo12amUcYG3fHQoH3LJTEi3142KLGWVzBfnYqhkinVe4Ep
+        sc6X3Iir1EZw+CkH5C7qPLc8xX64v+sackvKAjGLIQKBgDBIsu7EcoZzL6hmjW/F
+        JCVjaA6Smuor1XCMCHEa4aUl+1esv8ORvGwZq1bRsYDJD5U+K8+XxhiGzfg0IDW3
+        WkkpzNw1scQkU3nvHoC0JscUtYH3XBj3rIDrL8GB3jk+hevJCXv4Z04A/IRhjear
+        dHm9qjNOto+ucP7rWSkpUsn9
+    '''.decode("base64"))
+
+
+def decode_ecpoint(ecpoint):
+    return { "\x02": "compressed", "\x04": "uncompressed" }[ecpoint[0]], ecpoint[1:1+len(ecpoint)/2], ecpoint[1+len(ecpoint)/2:]
+
+def dumpasn1(der):
+    from subprocess import call
+    from tempfile import NamedTemporaryFile
+    with NamedTemporaryFile() as f:
+        f.write(der)
+        f.flush()
+        call(("dumpasn1", "-aop", f.name))
+
+if __name__ == "__main__":
+
+    show_manual_decode = False
+
+    ec_rfc5915           = DER_Decode(der_test_keys["ec_rfc5915"],  ECPrivateKey()  )[0]
+    ec_pkcs8             = DER_Decode(der_test_keys["ec_pkcs8"],    PrivateKeyInfo())[0]
+    ec_pkcs8_privateKey  = DER_Decode(str(ec_pkcs8["privateKey"]),  ECPrivateKey()  )[0]
+    rsa_rfc2313          = DER_Decode(der_test_keys["rsa_rfc2313"], RSAPrivateKey() )[0]
+    rsa_pkcs8            = DER_Decode(der_test_keys["rsa_pkcs8"],   PrivateKeyInfo())[0]
+    rsa_pkcs8_privateKey = DER_Decode(str(rsa_pkcs8["privateKey"]), RSAPrivateKey() )[0]
+
+    print
+    print "EC RFC 5915"
+    print ec_rfc5915.prettyPrint()
+
+    if show_manual_decode:
+        print
+        compressed, Qx, Qy = decode_ecpoint(ec_rfc5915["publicKey"].asOctets())
+        print "version:   ", ec_rfc5915["version"]
+        print "privateKey:", str(ec_rfc5915["privateKey"]).encode("hex")
+        print "parameters:", ec_rfc5915["parameters"]
+        print "publicKey: ", compressed
+        print "       Qx: ", Qx.encode("hex")
+        print "       Qy: ", Qy.encode("hex")
+
+    # This works, and lets .prettyPrint() display the ANY content properly,
+    # but it breaks some of the key hackery we do after all this display stuff.
+    #ec_pkcs8["privateKeyAlgorithm"]["parameters"] = DER_Decode(ec_pkcs8["privateKeyAlgorithm"]["parameters"])[0]
+
+    print
+    print "EC PKCS #8"
+    print ec_pkcs8.prettyPrint()
+    print ec_pkcs8_privateKey.prettyPrint()
+
+    if show_manual_decode:
+        print
+        compressed, Qx, Qy = decode_ecpoint(ec_pkcs8_privateKey["publicKey"].asOctets())
+        print "version:            ", ec_pkcs8["version"]
+        print "privateKeyAlgorithm:", ec_pkcs8["privateKeyAlgorithm"][0]
+        print "                    ", DER_Decode(ec_pkcs8["privateKeyAlgorithm"]["parameters"])[0]
+        print "privateKey:"
+        print "         version:   ", ec_pkcs8_privateKey["version"]
+        print "         privateKey:", str(ec_pkcs8_privateKey["privateKey"]).encode("hex")
+        print "         parameters:", ec_pkcs8_privateKey["parameters"]
+        print "         publicKey: ", compressed
+        print "                Qx: ", Qx.encode("hex")
+        print "                Qy: ", Qy.encode("hex")
+
+    print
+    print "RSA RFC 2313"
+    print rsa_rfc2313.prettyPrint()
+
+    if show_manual_decode:
+        print
+        print "version:", rsa_rfc2313["version"]
+        print "      n:", rsa_rfc2313["n"]
+        print "      e:", rsa_rfc2313["e"]
+        print "      d:", rsa_rfc2313["d"]
+        print "      p:", rsa_rfc2313["p"]
+        print "      q:", rsa_rfc2313["q"]
+        print "     dP:", rsa_rfc2313["dP"]
+        print "     dQ:", rsa_rfc2313["dQ"]
+        print "      u:", rsa_rfc2313["u"]
+
+    #rsa_pkcs8["privateKeyAlgorithm"]["parameters"] = DER_Decode(rsa_pkcs8["privateKeyAlgorithm"]["parameters"])[0]
+
+    print
+    print "RSA PKCS #8"
+    print rsa_pkcs8.prettyPrint()
+    print rsa_pkcs8_privateKey.prettyPrint()
+
+    if show_manual_decode:
+        print
+        print "version:            ", rsa_pkcs8["version"]
+        print "privateKeyAlgorithm:", rsa_pkcs8["privateKeyAlgorithm"][0]
+        print "privateKey:"
+        print "            version:", rsa_pkcs8_privateKey["version"]
+        print "                  n:", rsa_pkcs8_privateKey["n"]
+        print "                  e:", rsa_pkcs8_privateKey["e"]
+        print "                  d:", rsa_pkcs8_privateKey["d"]
+        print "                  p:", rsa_pkcs8_privateKey["p"]
+        print "                  q:", rsa_pkcs8_privateKey["q"]
+        print "                 dP:", rsa_pkcs8_privateKey["dP"]
+        print "                 dQ:", rsa_pkcs8_privateKey["dQ"]
+        print "                  u:", rsa_pkcs8_privateKey["u"]
+
+    # Generate PKCS #8 from ECPrivateKey and check against static data
+    p8 = PrivateKeyInfo()
+    ec = ECPrivateKey()
+    ec["version"]    = ec_rfc5915["version"]
+    ec["privateKey"] = ec_rfc5915["privateKey"]
+    ec["publicKey"]  = ec_rfc5915["publicKey"]
+    p8["version"] = 0
+    p8["privateKeyAlgorithm"] = AlgorithmIdentifier()
+    p8["privateKeyAlgorithm"]["algorithm"]  = "1.2.840.10045.2.1"
+    p8["privateKeyAlgorithm"]["parameters"] = ObjectIdentifier(ec_rfc5915["parameters"])
+    p8["privateKey"] = DER_Encode(ec)
+    der = DER_Encode(p8)
+    #print; dumpasn1(der)
+    #print; dumpasn1(der_test_keys["ec_pkcs8"])
+    print; print "Reencoded PKCS #8 {} static data".format("matches" if der == der_test_keys["ec_pkcs8"] else "doesn't match")
+
+    # Generate ECPrivateKey from  PKCS #8 and check against static data
+    ec = ECPrivateKey()
+    ec["version"]    = ec_pkcs8_privateKey["version"]
+    ec["privateKey"] = ec_pkcs8_privateKey["privateKey"]
+    ec["parameters"] = str(DER_Decode(ec_pkcs8["privateKeyAlgorithm"]["parameters"])[0])
+    ec["publicKey"]  = ec_pkcs8_privateKey["publicKey"]
+    der = DER_Encode(ec)
+    #print; dumpasn1(der)
+    #print; dumpasn1(der_test_keys["ec_rfc5915"])
+    print; print "Reencoded PKCS #8 {} static data".format("matches" if der == der_test_keys["ec_rfc5915"] else "doesn't match")
+
+    # Paranoia: Make sure we really can load the RFC 5915 we just generated.
+    from ecdsa.keys import SigningKey
+    sk = SigningKey.from_der(der)
+    print; print "ECDSA Python library parse of reencoded PKCS #8 data: {!r}".format(sk)



More information about the Commits mailing list