2
$\begingroup$

I created a random integer array of 32 bytes to use as my private key for secp256k1 curve.

const uint8_t secret[] = {0xb2,0x9a,0xc6,0xbd,0xc7,0x3d,0xc4,0xe1,
                          0x85,0xa7,0x3c,0x96,0xf8,0x1c,0x58,0x43,
                          0xe2,0xbf,0x2d,0x68,0xe5,0x6f,0xf6,0xae,
                          0x4f,0xe7,0x51,0xcd,0x9d,0x47,0x00,0xfa}

I want to turn this hex array into a ASN.1 DER encoded key so I can further use it with my hardware which expects the keys to be ASN.1 DER encoded.

Can you point me in the right direction on how to achieve this ?

Edit , I found an encoded key-pair, maybe I can pick up from this. Does the array below contain both public and private key parts ?

 keyPairData[] = { 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13,
    0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02,
    0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
    0x03, 0x01, 0x07, 0x04, 0x6D, 0x30, 0x6B, 0x02,
    0x01, 0x01, 0x04, 0x20, 0x78, 0xE5, 0x20, 0x6A,
    0x08, 0xED, 0xD2, 0x52, 0x36, 0x33, 0x8A, 0x24,
    0x84, 0xE4, 0x2F, 0x1F, 0x7D, 0x1F, 0x6D, 0x94,
    0x37, 0xA9, 0x95, 0x86, 0xDA, 0xFC, 0xD2, 0x23,
    0x6F, 0xA2, 0x87, 0x35, 0xA1, 0x44, 0x03, 0x42,
    0x00, 0x04, 0xED, 0xA7, 0xE9, 0x0B, 0xF9, 0x20,
    0xCF, 0xFB, 0x9D, 0xF6, 0xDB, 0xCE, 0xF7, 0x20,
    0xE1, 0x23, 0x8B, 0x3C, 0xEE, 0x84, 0x86, 0xD2,
    0x50, 0xE4, 0xDF, 0x30, 0x11, 0x50, 0x1A, 0x15,
    0x08, 0xA6, 0x2E, 0xD7, 0x49, 0x52, 0x78, 0x63,
    0x6E, 0x61, 0xE8, 0x5F, 0xED, 0xB0, 0x6D, 0x87,
    0x92, 0x0A, 0x04, 0x19, 0x14, 0xFE, 0x76, 0x63,
    0x55, 0xDF, 0xBD, 0x68, 0x61, 0x59, 0x31, 0x8E,
    0x68, 0x7C };
$\endgroup$
  • $\begingroup$ Thank you for the response Marteen. There is literally nothing in the documents other than the page where it says it expects ANSI X 9.62 formatted keys. $\endgroup$ – Dogus Ural Apr 26 at 9:27
  • $\begingroup$ I managed to find one example where they were using a encoded keypair. I edited my question which includes the keypair. $\endgroup$ – Dogus Ural Apr 26 at 9:27
  • $\begingroup$ Good luck: even ignoring encryption and binary-to-hex encodings, there exists several ASN.1 DER encodings of the same secp256k1 private key, depending on if optional fields of the spec are present. See this answer, and this example decoding of its example with a useful tool. $\endgroup$ – fgrieu Apr 26 at 12:55
  • 1
    $\begingroup$ @fgrieu I guess most libraries will accept a private key with or without public key point though. So I created an answer for the PKCS#8 formatted private key given in the question. Dogus, it's "Maarten" with a double A, pronounced as [a] as in "Hawaii". $\endgroup$ – Maarten Bodewes Apr 26 at 13:23
  • $\begingroup$ @MaartenBodewes: I had mixed results the few times I tried moving a private key across computer platforms other that for planned (re)deployment; and that was always RSA (thus things may have improved). Such transfer is rarely needed in production, and rarely tested. One issue I met was optional fields $p,q,d_p,d_q,q_\text{inv}$ required by X but rejected by Y. It would not be a surprise if something similar crept in the many hasty implementation of ECDSA with secp256k1. $\endgroup$ – fgrieu Apr 26 at 16:31
4
$\begingroup$

ASN.1 is a way of defining structures for data, and DER is a binary encoding of those structures. But they aren't describing any structures by themselves. Saying that something needs to be ASN.1 / DER encoded is like saying that the key needs to be represented in XML without specifying the tags or tree structure.


What you are required to generate is a PKCS#8 (inner) encoded private key. The SEC1 document link that I provided before defines the inner SEQUENCE in there. The PKCS#8 inner structure is used to identify the type of key. Most of what is in SEC1 was copied to X9.62. And yes, it clearly contains the optional public key. If you look for ways to encode your private key to PKCS#8 you'll find a lot more information. It's for instance the default encoding for OpenSSL, but most other libraries will use the same.

I can generate the same in Java (ECPrivateKey.getEncoded() for curve "secp256k1") but without the optional - and in my opinion spurious - public point included. You can see the structure you've provided in the Lapo online ASN.1 decoder. Yes, it clearly includes the public key as optional BIT STRING at the end (appending it yourself means adjusting the length encodings of the SEQUENCE's though).

If your structure lacks a public key, I would first just try and import it; it's pretty easy to compute the public key from the private key and parameters: just point multiplication with the base point G. Likely the device is capable of doing that.


You will generally want to create a "named" curve where the domain parameters are given by an OID (as in the example you've been given). It is more likely that explicit domain parameters are rejected by devices that only operate on a limited set of curves.

I've however encountered HSM's that require you to provide the unnamed parameters. In that case you may need to construct your private key using the explicit parameters and then encode...

| improve this answer | |
$\endgroup$
  • 1
    $\begingroup$ Java may depend on the provider(s) used. I get the publicpoint omitted for a key generated by Oracle/OpenJDK, but present for BouncyCastle or OpenSSL (via PKCS12). Bouncy also puts curve OID in the SEC1=inner part redundantly. Also PKCS8 isn't really 'the' default for OpenSSL; since 1.0.0 in 2010 some operations default to PKCS8 but others (still) don't, and some don't even support it. It is recommended on the PEM_{read,write}*_{keys,params,X509*} man page, FWTW :) $\endgroup$ – dave_thompson_085 Apr 27 at 7:38
  • $\begingroup$ Interesting, would you know if PKCS#8 is used for EC private keys? Of course, for me it is easy to add a public point to an ASN.1 structure in Java. But I guess doing such a thing might be a lot of work for a novice in the technologies used. $\endgroup$ – Maarten Bodewes Apr 27 at 11:34
  • $\begingroup$ I assume you mean if openssl commandline uses p8, because I couldn't answer for all programs using libcrypto, much less those using other middleware (except those using Java JCE). For output, since 1.0.0 genpkey pkey do for PEM but not DER and pkcs12 (input) and req -newkey -keyout do (PEM only). pkcs8 -topk8 always does and since 1.0.0 pkcs8 (from) also does for PEM but not DER. ec and ecparam -genkey don't. For input, everything that reads PEM except pkcs8 (from)accepts both p8 and trad, but reading DER is less consistent and too much work for now :-( $\endgroup$ – dave_thompson_085 Apr 30 at 10:43
  • $\begingroup$ Yeah, OpenSSL is a bit of a mess in that regard. I have no doubt that you can do many things through the API, it's a programming environment after all. So I was indeed talking command line. OK, so generally EC private keys are stored using some form of PKCS#8, and it can be configured to use it. Let's leave it at that, unless I have summed it up incorrectly. $\endgroup$ – Maarten Bodewes Apr 30 at 10:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.