【问题标题】:How to Encrypt/Decrypt text in a file in Java如何在 Java 中加密/解密文件中的文本
【发布时间】:2016-03-11 08:38:42
【问题描述】:

我的代码有问题,当我加密数据时,例如,在这种情况下,当我读取该文本文件并尝试解密它,使用接收者的私钥,我得到一个不同的密钥,因此我不能用它来解密加密的消息。

发件人代码:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

class Sender{

public static void main(String[] args) {
        //infile.txt
        File inFile = new File(args[0]);
        //outfile.txt
        File outFile = new File(args[1]);
        //mykeystore.jks
        File keyStoreFile = new File(args[2]);
        //mykeystore info
        String alias = args[3];
        String password = args[4];
        String storepass = args[5];
        //receptor certificate
        String receptorCert = args[6];

        try {
            //Read plain text
            FileInputStream rawDataFromFile = new FileInputStream(inFile);
            byte[] plainText = new byte[(int) inFile.length()];
            rawDataFromFile.read(plainText);

            //Create simmetric key
            String key = "Bar12345Bar12345"; // 128 bit key
            String initVector = "RandomInitVector"; // 16 bytes IV
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

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

            //Hash plaintext
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(plainText);
            byte[] digest = md.digest();

            //Encrypt simmetric key with receiver's public key          
            Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            PublicKey receptorPublicKey = getPublicKeyFromCert(receptorCert);
            rsaCipher.init(Cipher.ENCRYPT_MODE, receptorPublicKey);
            byte[] simmetricKey = rsaCipher.doFinal(skeySpec.getEncoded());

            //Encrypt hash with my private key
            KeyStore myKeyStore = KeyStore.getInstance("JKS");
            FileInputStream inStream = new FileInputStream(keyStoreFile);
            myKeyStore.load(inStream, storepass.toCharArray());
            PrivateKey privatekey = (PrivateKey) myKeyStore.getKey(alias, password.toCharArray());
            rsaCipher.init(Cipher.ENCRYPT_MODE, privatekey);            
            byte[] encodedHash = rsaCipher.doFinal(digest);

            //Write to outputfile
            FileOutputStream outToFile = new FileOutputStream(outFile);

            outToFile.write(simmetricKey);
            outToFile.write(encodedHash);
            outToFile.write(ciphertext);

            outToFile.close();
            rawDataFromFile.close();
        } catch (Exception e) {
            e.printStackTrace();
            e.getMessage();
        }
    }
    public static PublicKey getPublicKeyFromCert(String certLocation) {
        PublicKey pub = null;
        try {
            InputStream inStream = new FileInputStream(certLocation);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
            inStream.close();
            pub = (PublicKey) cert.getPublicKey();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return pub;
    }
}

收货人代码:

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class Receiver {

    public static void main(String[] args) {
        //Sender's out file
        File inFile = new File(args[0]);
        //receiver's keystore
        File keyStoreFile = new File(args[1]);
        //receiver's keystore info
        String password = args[2];
        String alias = args[3];
        String storepass = args[4];
        //sender's cetificate
        File cert = new File(args[5]);

        try {
            //get Sender's out file
            FileInputStream rawDataFromFile = new FileInputStream(inFile);
            byte[] simmetricKey = new byte[256];
            byte[] hash = new byte[256];
            byte[] message;

            rawDataFromFile.read(simmetricKey);
            rawDataFromFile.read(hash);

            int b = rawDataFromFile.available();
            message = new byte[b];

            rawDataFromFile.read(message);
            //decrypt the simmetric key with receiver's private key
            KeyStore myKeyStore = KeyStore.getInstance("JKS");
            FileInputStream inStream = new FileInputStream(keyStoreFile);
            myKeyStore.load(inStream, storepass.toCharArray());
            PrivateKey privatekey = (PrivateKey) myKeyStore.getKey(alias, password.toCharArray());
            //
            Cipher deCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            deCipher.init(Cipher.DECRYPT_MODE, privatekey);

            byte[] key = deCipher.doFinal(simmetricKey);

            System.out.println(Base64.encodeBase64String(key));

        } catch (Exception e) {
            System.out.println("Error del sistema " + e);
            e.printStackTrace();
        }

    }

}

更新:

现在我可以使用接收方的私钥解密 simmetric 密钥。但是当我加密消息时,我不知道如何使用相同的参数创建解码器。

用于加密纯文本的发件人代码。

    String key = "Bar12345Bar12345"; // 128 bit key
    String initVector = "RandomInitVector"; // 16 bytes IV
    IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
    System.out.println(iv.getIV());
    SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
    byte[] ciphertext = cipher.doFinal(plainText);

接收方解密1

    SecretKeySpec keySpec = new SecretKeySpec(decryptedKeySpec, "AES");
    Cipher decoder = Cipher.getInstance("AES");
    decoder.init(Cipher.DECRYPT_MODE, keyspec);
    byte[] original = descipher.doFinal(message);

错误:给定的最终块未正确填充

接收方解密2

    SecretKeySpec keySpec = new SecretKeySpec(decryptedKeySpec, "AES");
    Cipher decoder = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    decoder.init(Cipher.DECRYPT_MODE, keyspec);
    byte[] original = descipher.doFinal(message);

错误:缺少参数

最终更新: 现在我的代码可以工作了,感谢所有帮助。 这段代码可以从这里下载(顺便说一句,它是西班牙语,但我认为这并不重要):

download

【问题讨论】:

  • 会不会是您忘记在decoder.init() 中使用iv
  • 但是,iv 不是用来生成新密码的吗?我只想用 simmetric 密钥实例化一个密码。我一直在使用 IV 进行测试,但我得到了与原始文本不同的文本
  • 好的,我知道了,我没有收到不同的文本,这是我想要的文本,但它是 Base64,所以,我唯一要做的就是将它转换为这样的字符串:new String(myBase64),我会在这里更新代码,方便大家获取。
  • @SebastianTareB。下载链接坏了,请您更新您的最终解决方案。非常感谢。

标签: java encryption aes rsa keytool


【解决方案1】:

问题是您使用 AES 加密

SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); 密码密码 = Cipher.getInstance("AES/CBC/PKCS5PADDING");

而要破译, 您正在使用 RSA,

Cipher deCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

用于使用 AES 加密/解密的代码 sn-p

import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class EncryptionDecryptionAES {
    static Cipher cipher;

    public static void main(String[] args) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128);
        SecretKey secretKey = keyGenerator.generateKey();
        cipher = Cipher.getInstance("AES");

        String plainText = "AES Symmetric Encryption Decryption";
        System.out.println("Plain Text Before Encryption: " + plainText);

        String encryptedText = encrypt(plainText, secretKey);
        System.out.println("Encrypted Text After Encryption: " + encryptedText);

        String decryptedText = decrypt(encryptedText, secretKey);
        System.out.println("Decrypted Text After Decryption: " + decryptedText);
    }

    public static String encrypt(String plainText, SecretKey secretKey)
            throws Exception {
        byte[] plainTextByte = plainText.getBytes();
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedByte = cipher.doFinal(plainTextByte);
        Base64.Encoder encoder = Base64.getEncoder();
        String encryptedText = encoder.encodeToString(encryptedByte);
        return encryptedText;
    }

    public static String decrypt(String encryptedText, SecretKey secretKey)
            throws Exception {
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] encryptedTextByte = decoder.decode(encryptedText);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decryptedByte = cipher.doFinal(encryptedTextByte);
        String decryptedText = new String(decryptedByte);
        return decryptedText;
    }
}

请查看http://javapapers.com/java/java-symmetric-aes-encryption-decryption-using-jce/

【讨论】:

  • 如果对解决问题有帮助,请将答案标记为已接受。这样可以帮助其他寻找类似问题的人
  • 但是他用Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");byte[] simmetricKey = rsaCipher.doFinal(skeySpec.getEncoded());加密对称密钥
  • 我使用 AES 密钥加密消息,但我使用 RSA 公钥加密 AES 密钥,然后我尝试使用 RSA 私钥解密 AES 密钥。
  • @OmitsuDæmon 在您的接收程序中,您忘记使用AES解密。您直接使用了RSA算法。
【解决方案2】:

您的接收者似乎试图读取 256 字节 的加密对称密钥,但我认为 RSA 加密密钥只有 128 字节长。

所以也许它可以使用

byte[] simmetricKey = new byte[128];

【讨论】:

  • 我的 simmetricKey 是用一个 16 字节的字符串(密钥字符串(128 位))制作的,但加密后的 simmetricKey 是 256 字节长。 skeySpec 是 16 字节长。我在 Sender 类中进行了一些测试,一切正常,但是当我尝试通过文本文件发送数据时,问题就出现了。
  • 我只是在尝试你的代码,我得到了一个长度为 128 字节的加密密钥……你在保存之前打印了长度吗?您是否尝试打印出加密密钥的字节并使用十六进制编辑器将其与文件中的字节进行比较?
  • 不是,我只是打印了密钥解密的结果,并与原件对比
  • 结果如何?你用的是什么证书?
  • 我使用的是普通的 keytool 生成的证书和密钥库 (2048)。但是现在我认为它已经解决了,因为我可以解密密钥并且它与在发送者类中生成的相同。但现在我有另一个问题。我必须创建一个密码才能使用我解密的 simmetric 密钥进行解密。我用来加密的密码实例是“AES/CBC/PKCS5PADDING”,但我无法使用它解密,因为错误“缺少参数”,当我尝试仅使用“AES”时,它显示“给定最终块不正确填充”
猜你喜欢
  • 2011-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多