Information Security Stack Exchange is a question and answer site for information security professionals. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to set up ECDH-P521 in Java and in Javascript. When using Java to generate a random private key. The generated key is either 1106 or 1107 bytes long (numbers only): This is an example:


When generating a random number with a modified implementation of JSBN, the private key length is only 158 bytes long:


Now my question is: How long should the private key when using ECDH-P521R1?

share|improve this question
There is no one true format for keys. Some formats include envelopes, a description of the curve parameters... But no idea how you ended up with just a number. Those extended private keys are a sequence of bytes, not a decimal number. – CodesInChaos Apr 21 '13 at 11:12
A simple scalar (private key without any other information) should have about 157 decimal digits. – CodesInChaos Apr 21 '13 at 11:14
Yes, I'm just talking about the scalar. Do you have any idea why the generated scalar using bouncy castle is as huge as above? – JayBeOh Apr 21 '13 at 12:59
Please post some code. I guess that what BouncyCastle produced isn't just the scalar. – CodesInChaos Apr 21 '13 at 13:01
You're right. I didn't use the scalar but made the mistake to print out the encoded version of the private key object which of course was more. Thank you so much for your help! – JayBeOh Apr 21 '13 at 13:17
up vote 4 down vote accepted

Let's take your big integer, and convert it to binary, big-endian unsigned encoding (i.e. in Java, I call new BigInteger("...the big numer...").toByteArray() and I write that in a file, removing the leading 0x00 byte which toByteArray() added because it enforces signed encoding, and thus insists on a leading bit of value 0 if the value is positive). I get, indeed, a sequence of 1107 bytes which begins like this:

$ hd blob
00000000  30 82 04 4f 02 01 00 30  82 01 b9 06 07 2a 86 48  |0..O...0.....*.H|
00000010  ce 3d 02 01 30 82 01 ac  02 01 01 30 4d 06 07 2a  |.=..0......0M..*|
00000020  86 48 ce 3d 01 01 02 42  01 ff ff ff ff ff ff ff  |.H.=...B........|
00000030  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000060  ff ff ff ff ff ff ff ff  ff ff 30 81 88 04 42 01  |..........0...B.|
00000070  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
000000b0  fc 04 42 00 51 95 3e b9  61 8e 1c 9a 1f 92 9a 21  |..B.Q.>.a......!|
000000c0  a0 b6 85 40 ee a2 da 72  5b 99 b3 15 f3 b8 b4 89  |...@...r[.......|
000000d0  91 8e f1 09 e1 56 19 39  51 ec 7e 93 7b 16 52 c0  |.....V.9Q.~.{.R.|
000000e0  bd 3b b1 bf 07 35 73 df  88 3d 2c 34 f1 ef 45 1f  |.;...5s..=,4..E.|
000000f0  d4 6b 50 3f 00 04 81 85  04 00 c6 85 8e 06 b7 04  |.kP?............|
00000100  04 e9 cd 9e 3e cb 66 23  95 b4 42 9c 64 81 39 05  |....>.f#..B.d.9.|

The trained eye immediately recognizes the first bytes (30 82 04 4f 02 01 00...) as an encoded ASN.1 DER object (a SEQUENCE of length 0x44F, whose first element is an INTEGER of value 0). So that's not an integer at all ! Let's put it through OpenSSL:

$ openssl asn1parse -i -inform DER -in blob
    0:d=0  hl=4 l=1103 cons: SEQUENCE          
    4:d=1  hl=2 l=   1 prim:  INTEGER           :00
    7:d=1  hl=4 l= 441 cons:  SEQUENCE          
   11:d=2  hl=2 l=   7 prim:   OBJECT            :id-ecPublicKey
   20:d=2  hl=4 l= 428 cons:   SEQUENCE          
   24:d=3  hl=2 l=   1 prim:    INTEGER           :01
   27:d=3  hl=2 l=  77 cons:    SEQUENCE          
   29:d=4  hl=2 l=   7 prim:     OBJECT            :prime-field
  106:d=3  hl=3 l= 136 cons:    SEQUENCE          
  177:d=4  hl=2 l=  66 prim:     OCTET STRING      [HEX DUMP]:0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00
  245:d=3  hl=3 l= 133 prim:    OCTET STRING      [HEX DUMP]:0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650
  449:d=3  hl=2 l=   1 prim:    INTEGER           :01
  452:d=1  hl=4 l= 651 prim:  OCTET STRING      [HEX DUMP]:30820287020101044201945<...>

Now this looks a lot like an elliptic curve public/private key pair, tagged as such (the id-ecPublicKey object identifier). This means PKCS#8. We notice the elements describing the curve, beginning with the base field size (which is p = 2521-1), then the a and b parameters for the curve equation Y2 = X3 + aX + b (a = p - 3, which gives a slight performance bonus over other values), then the encoding of the conventional base point G (the "generator"), which is a sequence of bytes beginning with 0x04 (uncompressed encoding: the leading byte is followed by the big-endian encodings of the X and Y coordinates of G). The INTEGER immediately afterwards is the curve order n. These parameters match the definition of the P-521 curve (see FIPS 186-3, page 90).

The final OCTET STRING contains the private key. Let's use OpenSSL again to convert this PKCS#8 object into the internal format which OpenSSL prefers:

$ openssl pkcs8 -inform DER -in blob -nocrypt -out key.pem

(the -nocrypt flag tells to expect a key which is not password-protected). The resulting key.pem file can be then inspected:

$ openssl ec -in key.pem -text -noout
read EC key
Private-Key: (521 bit)
Field Type: prime-field

so here are your private and public keys, followed by (again) the curve definition parameters.

An elliptic curve private key is an integer in the 1..n-1 range, where n is the order of the conventional base point. Normally, n is a prime integer (the curve has been selected for that). In the case of the standard NIST curves on prime fields, the base point generates whole curve, which has prime order, and n is close to p (indeed, |p+1-n| <= 2*sqrt(p) by Hasse's theorem). So the private key will be, in the case of P-521, an integer of at most 521 bits, potentially at bit smaller (but very rarely much smaller).

share|improve this answer
Thanks a lot for your detailed answer. My problem was already solved by CodesInChaos. Yet it's great to get such thorough insight into the way the key file is encoded! – JayBeOh Apr 21 '13 at 15:03

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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