Pergunta

Este código gera um par de chaves públicas/privadas:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keypair = keyGen.genKeyPair();
PrivateKey privateKey = keypair.getPrivate();
PublicKey publicKey = keypair.getPublic();

O que eu gostaria de saber é como você costuma armazenar a chave pública:

Opção 1: Armazene os bytes

byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
// ... write to file

// convert bytes back to public/private keys
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

O que eu não gosto é vincular o código a implementações concretas, como PKCS8EncodedKeySpec e X509EncodedKeySpec.

Opção 2: Armazene o módulo e o expoente

KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey, RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,RSAPrivateKeySpec.class);

// store modulus and exponent as BigIntegers
BigInteger modulus = pub.getModulus());
BigInteger exponent = pub.getPublicExponent());
// ... write to file

// recreate public key (the same applies to the private key)
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);

A segunda opção é mais fácil de implementar, mas não sei se pode ser menos executado.

Algum conselho?

Foi útil?

Solução

Em nossas aplicações, armazenamos chaves públicas e privadas no formato Der para que possam ser usadas e manipuladas fora do Java com mais facilidade. No nosso caso, as teclas privadas não têm senhas.

Para converter a chave privada para algo mais facilmente utilizável em Java:

openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER

Então você pode obter uma chave privada da RSA diretamente por:

public static RSAPrivateKey getPrivateKey(File privateKeyFile) throws IOException, GeneralSecurityException {
    byte[] keyBytes = new byte[(int)privateKeyFile.length()];
    FileInputStream fis = new FileInputStream(privateKeyFile);
    fis.read(keyBytes);
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(spec);
    return privKey;
}

A chave pública é semelhante:

openssl rsa -in private.pem -pubout -outform DER -out public.der

E para ler:

public static RSAPublicKey getPublicKey(File publicKeyFile) throws IOException, GeneralSecurityException {
    byte[] keyBytes = new byte[(int)publicKeyFile.length()];
    FileInputStream fis = new FileInputStream(publicKeyFile);
    fis.read(keyBytes);
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory factory = KeyFactory.getInstance("RSA");
    RSAPublicKey pubKey = (RSAPublicKey)factory.generatePublic(publicKeySpec);
    return pubKey;
}

Muitas pessoas armazenam então chaveiros. Para nossos propósitos, precisávamos da mesma chave para ser compartilhada em vários aplicativos em vários idiomas diferentes e não queríamos duplicar os arquivos no disco.

Em ambos os casos, o desempenho não deve ser uma grande preocupação, porque é provável que você guarde essas chaves em algum tipo de singleton ou cache, em vez de regenerá -las a cada vez.

Outras dicas

Você está realmente armazenando os bytes em ambos os casos, se você percebe ou não. Suponho que a resposta correta é sugerida na resposta @Brian M. Carr, que é armazenar o objeto de nível superior em sua forma mais natural. No caso das chaves públicas, as escolhas óbvias são como uma estrutura PKCS#1 RsapublicKey ASN.1, codificada por der Der, ou como uma estrutura de subtitedPublicKeyInFo ASN.1, codificada por Der. Este último é o que os provedores do Sol oferecem, que o Sun Class X509EncodedKeyspec suporta. Da mesma forma, o PKCS8ENCODEDKEYSPEC suporta um formato de chave privado. Ambos os formatos são padrões e são suportados pelo OpenSSL, por exemplo. O Sun tende - tendia :( - para apoiar os padrões existentes, em vez de definir os seus.

Se você deseja definir um formato para armazenar as teclas, eu escolheria um formato dispensável para que ele não quebre quando você deseja alterar a criptografia (quando o antigo fica fraco, por exemplo).

Então, eu armazenaria os bytes codificados como Base64, juntamente com uma string que descreve o formato, "RSA", talvez.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top