AES + RSA加密产生垃圾字符



我正在尝试使用AES和RSA加密和解密XML文件,但在解密后得到一些垃圾字符。

package com.example.demo.junk;

import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Duration;
import java.time.Instant;
public class EncryptionPOC {
private static IvParameterSpec getIv() {
SecureRandom srandom = new SecureRandom();
byte[] iv = new byte[128 / 8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
//Save it.
try (FileOutputStream fos = new FileOutputStream("iv.file")) {
fos.write(iv);
} catch (Exception e) {
throw new RuntimeException(e);
}
return ivspec;
}
private static SecretKey getSecretKey(String algorithm) {
try {
KeyGenerator kgen = KeyGenerator.getInstance(algorithm);
kgen.init(128);
return kgen.generateKey();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static PrivateKey loadPrivateKey() {
try {
byte[] bytes = Files.readAllBytes(Paths.get("private.key"));
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey pvt = kf.generatePrivate(ks);
return pvt;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static KeyPair getKeyPair(String algorithm) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(algorithm);
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
return keyPair;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static void writeContent(IvParameterSpec ivspec, PrivateKey privateKey, SecretKey secretKey) {
try {
FileOutputStream out = new FileOutputStream("Manifest-Encrypted.enc");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] b = cipher.doFinal(secretKey.getEncoded());
out.write(b);
Cipher ci = Cipher.getInstance("AES/CBC/ISO10126Padding");
ci.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
try (FileInputStream in = new FileInputStream("Manifest1.xml")) {
processFileForAes(ci, in, out);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void readContent() {
try {
byte[] bytes = Files.readAllBytes(Paths.get("public.pub"));
X509EncodedKeySpec ks = new X509EncodedKeySpec(bytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub = kf.generatePublic(ks);
FileInputStream in = new FileInputStream("Manifest-Encrypted.enc");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, pub);
byte[] b = new byte[256];
in.read(b);
byte[] keyb = cipher.doFinal(b);
SecretKeySpec skey = new SecretKeySpec(keyb, "AES");
byte[] iv = new byte[128 / 8];
FileInputStream fis = new FileInputStream("iv.file");
fis.read(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher ci = Cipher.getInstance("AES/CBC/ISO10126Padding");
ci.init(Cipher.DECRYPT_MODE, skey, ivspec);
try (FileOutputStream out = new FileOutputStream("Manifest2.xml")) {
processFile(ci, in, out);
readFile("Manifest2.xml");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void readFile(String fileName) throws IOException {
try(FileInputStream out = new FileInputStream(fileName)) {
int i;
while ((i = out.read()) != -1) {
System.out.print((char) i);
}
System.out.println();
}
}

//  ////////////////////////////////////////////////////////////////////////////////////////
private static void saveKeypair(KeyPair keyPair) {
try (FileOutputStream out = new FileOutputStream("private.key")) {
out.write(keyPair.getPrivate().getEncoded());
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
try (FileOutputStream out = new FileOutputStream("public.pub")) {
out.write(keyPair.getPublic().getEncoded());
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

public static void RSAEncryption(PrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
try (FileOutputStream out = new FileOutputStream("Doc-enc.des");
FileInputStream in = new FileInputStream("File1.deb")) {
processFile(cipher, in, out);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private static void processFile(Cipher ci, InputStream in, OutputStream out)
throws javax.crypto.IllegalBlockSizeException,
javax.crypto.BadPaddingException,
java.io.IOException {
byte[] ibuf = new byte[1024];
int len;
while ((len = in.read(ibuf)) != -1) {
byte[] obuf = ci.update(ibuf, 0, len);
if (obuf != null)
{
out.write(obuf);
}
}
byte[] obuf = ci.doFinal();
if (obuf != null) out.write(obuf);
}

static private void processFileForAes(Cipher ci, InputStream in, OutputStream out)
throws javax.crypto.IllegalBlockSizeException,
javax.crypto.BadPaddingException,
java.io.IOException {
byte[] ibuf = new byte[1024];
int len;
while ((len = in.read(ibuf)) != -1) {
byte[] obuf = ci.update(ibuf, 0, len);
if (obuf != null) out.write(obuf);
}
byte[] obuf = ci.doFinal();
if (obuf != null) out.write(obuf);
}
public static void main(String[] args) {
//      Instant in1 = Instant.now();
//      KeyPair keyPair = getKeyPair("RSA");
//      saveKeypair(keyPair);
//      RSAEncryption(keyPair.getPrivate());
//      Instant in2 = Instant.now();
//
//      Duration duration = Duration.between(in1, in2);
//      System.out.println(duration.toMillis());
//KeyPair keyPair = getKeyPair("RSA");
//saveKeypair(keyPair);
//        Instant in1 = Instant.now();
//        SecretKey secretKey = getSecretKey("AES");
//        IvParameterSpec ivs = getIv();
//        PrivateKey privateKey = loadPrivateKey();
//        writeContent(ivs, privateKey, secretKey);
//        Instant in2 = Instant.now();
readContent();
//Duration duration = Duration.between(in1, in2);
//System.out.println(duration.toMillis());
}
}

输出:

* *�# y ' X��,f(�{��declaration"在1176年* *

对于某些文件,我得到正确的输出,但对于某些文件,它在开始时给出垃圾字符。这个问题可能的根本原因是什么?

主要问题是,当您创建密文时,您似乎将IV写入一个单独的文件,并假设在解密它时将其写入文件的前面。

此外,即使您使用流API从正确的位置获取内容字节,您也应该意识到JavaInputStream.read()可能不会读取缓冲区值的字节。相反,您应该使用InputStream#readNBytes(int)来获得更简洁的代码。

我也强烈建议你适当地处理你的异常,并使用try-with-resources。

最新更新