2014-06-21 6 views
6

Ho cercato questo per le ultime 4-5 ore e non riesco a trovare una risposta che in realtà funziona nonostante abbia trovato "risposte" che usavano tutto da un alcuni metodi per un'intera ~ 100 linea di classe. Non riesco a immaginare che non ci sia una semplice funzione per fare una cosa così banale: PJava: crittografare la stringa con il file di chiave pubblica esistente

Ho un set preesistente di chiavi pubbliche/private (in realtà, due set - uno generato da ssh-keygen e un altro di openssl quindi .. qualunque formato funzioni sia bello).

Tutto quello che sono, dopo è un semplice Java equivalente a quello che scrivo in pitone come -

key_object = someModule.KeyObject(nameOfPublicKeyFile) 

def encrypt (SomePlainText) : 
    return someOtherModule.encrypt(key_object, SomePlainText) 

Qualsiasi aiuto sarebbe fantastico!

risposta

34

Questi comandi openssl nella shell creano una coppia di chiavi RSA e scrivono le chiavi pubbliche e private su file formattati DER.

Qui, il file della chiave privata non è protetto da password (-nocrypt) per semplificare le cose.

$ openssl genrsa -out keypair.pem 2048 
Generating RSA private key, 2048 bit long modulus 
............+++ 
................................+++ 
e is 65537 (0x10001) 
$ openssl rsa -in keypair.pem -outform DER -pubout -out public.der 
writing RSA key 
$ openssl pkcs8 -topk8 -nocrypt -in keypair.pem -outform DER -out private.der 

Ora che avete i file DER, li si può leggere in Java e utilizzare KeySpec e KeyFactory per creare PublicKey e PrivateKey oggetti.

public byte[] readFileBytes(String filename) throws IOException 
{ 
    Path path = Paths.get(filename); 
    return Files.readAllBytes(path);   
} 

public PublicKey readPublicKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException 
{ 
    X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(readFileBytes(filename)); 
    KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
    return keyFactory.generatePublic(publicSpec);  
} 

public PrivateKey readPrivateKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException 
{ 
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(readFileBytes(filename)); 
    KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
    return keyFactory.generatePrivate(keySpec);  
} 

Con le chiavi pubbliche e private, è possibile crittografare e decrittografare piccole quantità di dati (che si adattano all'interno del vostro modulo di RSA.) Vi consiglio OAEP imbottitura.

public byte[] encrypt(PublicKey key, byte[] plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
{ 
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding"); 
    cipher.init(Cipher.ENCRYPT_MODE, key); 
    return cipher.doFinal(plaintext); 
} 

public byte[] decrypt(PrivateKey key, byte[] ciphertext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
{ 
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, key); 
    return cipher.doFinal(ciphertext); 
} 

Qui è legato insieme con un semplice crittografia e la decrittografia:

public void Hello() 
{ 
    try 
    { 
     PublicKey publicKey = readPublicKey("public.der"); 
     PrivateKey privateKey = readPrivateKey("private.der"); 
     byte[] message = "Hello World".getBytes("UTF8"); 
     byte[] secret = encrypt(publicKey, message); 
     byte[] recovered_message = decrypt(privateKey, secret); 
     System.out.println(new String(recovered_message, "UTF8")); 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
} 
+0

Grazie! Ci provo stasera. – user2877564

+0

Risposta eccellente, ricevo solo java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: formato della chiave non valido durante la lettura del file chiave per generare la chiave. So che potrebbe essere correlato al formato del file. A cosa dovrei fare attenzione? – Merrin

+0

Sto cercando di usare un file pem a proposito. – Merrin

1

Mi piacerebbe condividere un pezzo di codice .. beh in realtà un'intera classe che può fare ciò che si richiede se lo si personalizza per le proprie esigenze. Ho usato questo in una delle mie applicazioni in cui ho usato per crittografare/decifrare un file con le chiavi pubbliche/private generate. Lo stesso può essere applicato anche alle stringhe.

import java.security.*; 
import java.security.spec.*; 
import javax.crypto.*; 
import javax.crypto.spec.*; 
import java.io.*; 
import java.util.*; 

/** 
* This class encrypts and decrypts a file using CipherStreams 
* and a 256-bit Rijndael key. The key is then encrypted using 
* a 1024-bit RSA key, which is password-encrypted. 
*/ 
public class FileEncryptorRSA { 
    /** 
    * When files are encrypted, this will be appended to the end 
    * of the filename. 
    */ 
    private static final String ENCRYPTED_FILENAME_SUFFIX=".encrypted"; 

    /** 
    * When files are decrypted, this will be appended to the end 
    * of the filename. 
    */ 
    private static final String DECRYPTED_FILENAME_SUFFIX=".decrypted"; 

    /** 
    * Number of times the password will be hashed with MD5 
    * when transforming it into a TripleDES key. 
    */ 
    private static final int ITERATIONS = 1000; 

    /** 
    * FileEncryptor is started with one of three options: 
    * 
    * -c: create key pair and write it to 2 files 
    * -e: encrypt a file, given as an argument 
    * -d: decrypt a file, given as an argument 
    */ 
    public static void main (String[] args) 
    throws Exception { 
    if ((args.length < 1) || (args.length > 2)) { 
     usage(); 
    } else if ("-c".equals(args[0])) { 
     createKey(); 
    } else if ("-e".equals(args[0])) { 
     encrypt(args[1]); 
    } else if ("-d".equals(args[0])) { 
     decrypt(args[1]); 
    } else { 
     usage(); 
    } 
    } 

    private static void usage() { 
    System.err.println("Usage: java FileEncryptor -c|-e|-d [filename]"); 
    System.exit(1); 
    } 

    /** 
    * Creates a 1024 bit RSA key and stores it to 
    * the filesystem as two files. 
    */ 
    private static void createKey() 
    throws Exception { 
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 
    System.out.print("Password to encrypt the private key: "); 
    String password = in.readLine(); 
    System.out.println("Generating an RSA keypair..."); 

    // Create an RSA key 
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 
    keyPairGenerator.initialize(1024); 
    KeyPair keyPair = keyPairGenerator.genKeyPair(); 

    System.out.println("Done generating the keypair.\n"); 

    // Now we need to write the public key out to a file 
    System.out.print("Public key filename: "); 
    String publicKeyFilename = in.readLine(); 

    // Get the encoded form of the public key so we can 
    // use it again in the future. This is X.509 by default. 
    byte[] publicKeyBytes = keyPair.getPublic().getEncoded(); 

    // Write the encoded public key out to the filesystem 
    FileOutputStream fos = new FileOutputStream(publicKeyFilename); 
    fos.write(publicKeyBytes); 
    fos.close(); 

    // Now we need to do the same thing with the private key, 
    // but we need to password encrypt it as well. 
    System.out.print("Private key filename: "); 
    String privateKeyFilename = in.readLine(); 

    // Get the encoded form. This is PKCS#8 by default. 
    byte[] privateKeyBytes = keyPair.getPrivate().getEncoded(); 

    // Here we actually encrypt the private key 
    byte[] encryptedPrivateKeyBytes = 
    passwordEncrypt(password.toCharArray(),privateKeyBytes); 

    fos = new FileOutputStream(privateKeyFilename); 
    fos.write(encryptedPrivateKeyBytes); 
    fos.close(); 
    } 

    /** 
    * Encrypt the given file with a session key encrypted with an 
    * RSA public key which will be read in from the filesystem. 
    */ 
    private static void encrypt(String fileInput) 
    throws Exception { 

    BufferedReader in = new BufferedReader 
    (new InputStreamReader(System.in)); 
    System.out.print("Public Key to encrypt with: "); 
    String publicKeyFilename = in.readLine(); 

    // Load the public key bytes 
    FileInputStream fis = new FileInputStream(publicKeyFilename); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

    int theByte = 0; 
    while ((theByte = fis.read()) != -1) 
    { 
     baos.write(theByte); 
    } 
    fis.close(); 

    byte[] keyBytes = baos.toByteArray(); 
    baos.close(); 

    // Turn the encoded key into a real RSA public key. 
    // Public keys are encoded in X.509. 
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); 
    KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
    PublicKey publicKey = keyFactory.generatePublic(keySpec); 

    // Open up an output file for the output of the encryption 
    String fileOutput = fileInput + ENCRYPTED_FILENAME_SUFFIX; 
    DataOutputStream output = new DataOutputStream 
    (new FileOutputStream(fileOutput)); 

    // Create a cipher using that key to initialize it 
    Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 
    rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey); 

    // Now create a new 256 bit Rijndael key to encrypt the file itself. 
    // This will be the session key. 
    KeyGenerator rijndaelKeyGenerator = KeyGenerator.getInstance("Rijndael"); 
    rijndaelKeyGenerator.init(256); 
    System.out.println("Generating session key..."); 
    Key rijndaelKey = rijndaelKeyGenerator.generateKey(); 
    System.out.println("Done generating key."); 

    // Encrypt the Rijndael key with the RSA cipher 
    // and write it to the beginning of the file. 
    byte[] encodedKeyBytes= rsaCipher.doFinal(rijndaelKey.getEncoded()); 
    output.writeInt(encodedKeyBytes.length); 
    output.write(encodedKeyBytes); 

    // Now we need an Initialization Vector for the symmetric cipher in CBC mode 
    SecureRandom random = new SecureRandom(); 
    byte[] iv = new byte[16]; 
    random.nextBytes(iv); 

    // Write the IV out to the file. 
    output.write(iv); 
    IvParameterSpec spec = new IvParameterSpec(iv); 

    // Create the cipher for encrypting the file itself. 
    Cipher symmetricCipher = Cipher.getInstance("Rijndael/CBC/PKCS5Padding"); 
    symmetricCipher.init(Cipher.ENCRYPT_MODE, rijndaelKey, spec); 

    CipherOutputStream cos = new CipherOutputStream(output, symmetricCipher); 

    System.out.println("Encrypting the file..."); 

    FileInputStream input = new FileInputStream(fileInput); 

    theByte = 0; 
    while ((theByte = input.read()) != -1) 
    { 
     cos.write(theByte); 
    } 
    input.close(); 
    cos.close(); 
    System.out.println("File encrypted."); 
    return; 
    } 

    /** 
    * Decrypt the given file. 
    * Start by getting the RSA private key 
    * and decrypting the session key embedded 
    * in the file. Then decrypt the file with 
    * that session key. 
    */ 
    private static void decrypt(String fileInput) 
    throws Exception { 

    BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 
    System.out.print("Private Key to decrypt with: "); 
    String privateKeyFilename = in.readLine(); 

    System.out.print("Password for the private key: "); 
    String password = in.readLine(); 

    // Load the private key bytes 
    FileInputStream fis = new FileInputStream(privateKeyFilename); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

    int theByte = 0; 
    while ((theByte = fis.read()) != -1) 
    { 
     baos.write(theByte); 
    } 
    fis.close(); 

    byte[] keyBytes = baos.toByteArray(); 
    baos.close(); 

    keyBytes = passwordDecrypt(password.toCharArray(), keyBytes); 

    // Turn the encoded key into a real RSA private key. 
    // Private keys are encoded in PKCS#8. 
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); 
    KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
    PrivateKey privateKey = keyFactory.generatePrivate(keySpec); 

    // Create a cipher using that key to initialize it 
    Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 

    // Read in the encrypted bytes of the session key 
    DataInputStream dis = new DataInputStream(new FileInputStream(fileInput)); 
    byte[] encryptedKeyBytes = new byte[dis.readInt()]; 
    dis.readFully(encryptedKeyBytes); 

    // Decrypt the session key bytes. 
    rsaCipher.init(Cipher.DECRYPT_MODE, privateKey); 
    byte[] rijndaelKeyBytes = rsaCipher.doFinal(encryptedKeyBytes); 

    // Transform the key bytes into an actual key. 
    SecretKey rijndaelKey = new SecretKeySpec(rijndaelKeyBytes, "Rijndael"); 

    // Read in the Initialization Vector from the file. 
    byte[] iv = new byte[16]; 
    dis.read(iv); 
    IvParameterSpec spec = new IvParameterSpec(iv); 

    Cipher cipher = Cipher.getInstance("Rijndael/CBC/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, rijndaelKey, spec); 
    CipherInputStream cis = new CipherInputStream(dis, cipher); 

    System.out.println("Decrypting the file..."); 
    FileOutputStream fos = new FileOutputStream(fileInput + DECRYPTED_FILENAME_SUFFIX); 

    // Read through the file, decrypting each byte. 
    theByte = 0; 
    while ((theByte = cis.read()) != -1) 
    { 
     fos.write(theByte); 
    } 
    cis.close(); 
    fos.close(); 
    System.out.println("Done."); 
    return; 
    } 

    /** 
    * Utility method to encrypt a byte array with a given password. 
    * Salt will be the first 8 bytes of the byte array returned. 
    */ 
    private static byte[] passwordEncrypt(char[] password, byte[] plaintext) throws Exception { 

    // Create the salt. 
    byte[] salt = new byte[8]; 
    Random random = new Random(); 
    random.nextBytes(salt); 

    // Create a PBE key and cipher. 
    PBEKeySpec keySpec = new PBEKeySpec(password); 
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwofish-CBC"); 
    SecretKey key = keyFactory.generateSecret(keySpec); 
    PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS); 
    Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwofish-CBC"); 
    cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); 

    // Encrypt the array 
    byte[] ciphertext = cipher.doFinal(plaintext); 

    // Write out the salt, then the ciphertext and return it. 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    baos.write(salt); 
    baos.write(ciphertext); 
    return baos.toByteArray(); 
    } 

    /** 
    * Utility method to decrypt a byte array with a given password. 
    * Salt will be the first 8 bytes in the array passed in. 
    */ 
    private static byte[] passwordDecrypt(char[] password, byte[] ciphertext) throws Exception { 

    // Read in the salt. 
    byte[] salt = new byte[8]; 
    ByteArrayInputStream bais = new ByteArrayInputStream(ciphertext); 
    bais.read(salt,0,8); 

    // The remaining bytes are the actual ciphertext. 
    byte[] remainingCiphertext = new byte[ciphertext.length-8]; 
    bais.read(remainingCiphertext,0,ciphertext.length-8); 

    // Create a PBE cipher to decrypt the byte array. 
    PBEKeySpec keySpec = new PBEKeySpec(password); 
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwofish-CBC"); 
    SecretKey key = keyFactory.generateSecret(keySpec); 
    PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS); 
    Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwofish-CBC"); 

    // Perform the actual decryption. 
    cipher.init(Cipher.DECRYPT_MODE, key, paramSpec); 
    return cipher.doFinal(remainingCiphertext); 
    } 
} 

EDIT:

Avrete bisogno di cambiare la politica Java di voi JVM (Java Cryptography Extension JCE) illimitato Forza Foro competente per l'utilizzo di questo codice. Tutte le informazioni correlate quanto riguarda il cambiamento nella politica Java può essere trovato HERE

1

Ecco un buon esempio:

e ci sono molti di più. (Google per "java crittografare RSA esempio" se questo link si rompe.)


io non riesco a trovare una risposta che funziona realmente

provare l'uno linkato sopra. Se non funziona, ti preghiamo di seguire una modifica o un commento per dire cosa non va.

Non riesco a immaginare che non ci sia una semplice funzione per fare una cosa così banale. : P

Beh mi dispiace, ma la vostra immaginazione deve essere rotto :-)

In realtà, non è una cosa banale. Ed è reso più difficile dal fatto che Java sta cercando di supportare una vasta gamma di funzionalità crittografiche e stack di tecnologie crittografiche utilizzando un'unica API unificata.

Problemi correlati