Java - 加密字符串与现有的公钥文件

问题描述:

我一直在研究这个过去4-5小时现在,似乎无法找到一个答案,实际上工作尽管找到'答案',使用一切从一个整个〜100线类的方法很少。我无法想象有没有一些简单的功能来做这样一件小事:PJava - 加密字符串与现有的公钥文件

我有一个预先存在的一组公钥/私钥(实际上,两组 - 一个由ssh-keygen生成,另一个由openssl所以..任何格式的作品都很酷)。

所有我追求的是一个简单的java相当于我在python写这样 -

key_object = someModule.KeyObject(nameOfPublicKeyFile) 

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

任何帮助将真棒!

shell中的这些openssl命令创建一个RSA密钥对,并将公钥和私钥写入DER格式文件。

这里,私钥文件没有密码保护(-nocrypt)以保持简单。

$ 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 

现在,你有DER文件,你可以在Java阅读和使用KeySpec的KeyFactory创建公钥专用密钥对象。

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);  
} 

随着公共和私有密钥,您可以加密和解密少量数据(您的RSA模内贴合。)我建议OAEP填充。

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); 
} 

这是一个简单的加密和解密绑在一起:

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

谢谢!我今天晚上会去。 – user2877564

+0

伟大的答案,只有我得到一个java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:无效的密钥格式,同时读取密钥文件回来生成密钥。我知道它可能与文件格式有关。我应该注意什么? – Merrin

+0

我正在尝试使用pem文件。 – Merrin

我想分享一段代码......实际上,如果您根据自己的需要对其进行自定义,则可以完成您所需的全部课程。我已经在我的一个应用程序中使用过这个功能,我曾用这个应用程序用生成的公钥/私钥对文件进行加密/解密。同样可以应用于字符串。

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); 
    } 
} 

编辑:

你需要改变你的Java政策的JVM Java加密扩展(JCE)无限强度辖区使用该代码。 关于JAVA政策变化的所有相关信息,可以发现HERE

这里是一个很好的例子:

,并有更多的。 (谷歌对于如果此链接中断的“Java加密RSA例子”。)


我似乎无法找到实际工作

尝试一个上面链接的答案。如果它不起作用,请跟进编辑或评论以说明发生了什么问题。

我无法想象有没有一些简单的功能来做这种小事。 :P

好抱歉,但你的想象力必须:-)

事实上被打破,它不是一个简单的事情。由于Java试图使用单一的统一API来支持各种各样的加密功能和加密技术栈,使得它变得更加困难。