Longueur de clé privée de courbe elliptique en Java
J'ai créé une paire de clés EC en utilisant la courbe "secp256r1". Il s'agit d'une courbe de 256 bits et la clé privée doit être de 256 bits (32 octets). Mais ce que j'obtiens, c'est une clé privée de 39 octets. Voici mon code
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); //Provider is SunEC version 1.8
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
kpg.initialize(ecSpec, new SecureRandom());
KeyPair ecKeyPair = kpg.generateKeyPair();
PrivateKey privateKey = ecKeyPair.getPrivate();
ASN1Sequence sequence = DERSequence.getInstance(privateKey.getEncoded());
DEROctetString subjectPrivateKey = (DEROctetString) sequence.getObjectAt(2);
byte[] privateKeyBytes = subjectPrivateKey.getOctets();
System.out.println("PrivateKeyBytes.length: " + privateKeyBytes.length); // Expected length is 32, but actual is 39
J'utilise JDK 1.8.0_144 et la bibliothèque BouncyCastle. Voici pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>pki</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-debug-jdk15on</artifactId>
<version>1.65</version>
</dependency>
</dependencies>
</project>
Comment obtenir 32 octets de clé privée ?
Réponses
La partie dépendante de l'algorithme de PKCS8, à l'élément #2 de la séquence, pour EC est elle-même un codage DER, de la structure SEC1 ECPrivateKey, également documentée à rfc5915 . Pour SunEC, il s'agit d'une SEQUENCE de version INTEGER et OCTETSTRING contenant les octets réels de la clé privée ; les paramètres optionnels context-0 et context-1 publickey sont omis. Vous devez donc analyser cela :
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC",args[0]);
kpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
KeyPair ecKeyPair = kpg.generateKeyPair();
PrivateKey privateKey = ecKeyPair.getPrivate();
byte[] pkcs8 = privateKey.getEncoded();
// slightly reorganized
DEROctetString wrapped = (DEROctetString) DERSequence.getInstance(pkcs8).getObjectAt(2);
System.out.println (wrapped.getOctets().length);
// added
DEROctetString raw = (DEROctetString) DERSequence.getInstance( wrapped.getOctets() ).getObjectAt(1);
System.out.println (raw.getOctets().length);
Puisque vous utilisez BouncyCastle, plutôt que d'analyser manuellement le PKCS8, vous pouvez utiliser la classe BouncyCastle pour org.bouncycastle.asn1.pkcs.PrivateKeyInfo:
PrivateKeyInfo info = PrivateKeyInfo.getInstance (DERSequence.getInstance(pkcs8));
DEROctetString raw2 = (DEROctetString)( DERSequence.getInstance(info.parsePrivateKey()) ).getObjectAt(1);
System.out.println (raw2.getOctets().length);
et enfin, plutôt que de passer par l'encodage, vous pouvez obtenir la valeur de la clé privée directement à partir de l' ECPrivateKeyobjet en tant que BigIntegervaleur, qui peut être convertie en un tableau d'octets, bien qu'elle soit de longueur variable au lieu de la longueur fixe traditionnellement utilisée pour les clés privées EC, donc vous devrez peut-être l'ajuster:
byte[] bytes = ((ECPrivateKey)privateKey).getS().toByteArray();
System.out.println(bytes.length);
// may need left-trim or pad with zero(s)