Java 如何在android中使用RSA进行加密和解密

Java 如何在android中使用RSA进行加密和解密,java,android,encryption,cryptography,rsa,Java,Android,Encryption,Cryptography,Rsa,我正试图用我的助手类加密和解密图像文件 rsaheloper.java package com.lib; import java.io.FileInputStream; import java.io.FileOutputStream; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateK

我正试图用我的助手类加密和解密图像文件
rsaheloper.java

package com.lib;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;

/**
 * Created by shobhan.
 */
public class RSAHelper {
    private final static String RSA = "RSA";

    private PublicKey publicKey;
    private PrivateKey privateKey;

    public RSAHelper() throws Exception {
        /**
         * generate RSA keys
         */
        generateKey();
    }

    private void generateKey() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA);
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        publicKey = keyPair.getPublic();
        privateKey = keyPair.getPrivate();
    }

    /**
     * Used to do encryptFile the file
     *
     * @param srcPath  File path to be encrypted
     * @param destPath Encrypts the file in srcPath and creates a file in destPath
     * @return true if encryption success, false otherwise
     */
    public boolean encryptFile(String srcPath, String destPath) {

        try {
            FileInputStream fileInputStream = new FileInputStream(srcPath);
            FileOutputStream fileOutputStream = new FileOutputStream(destPath);

            // byte[] key = "12345678".getBytes();
            // SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);

            Cipher cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.PUBLIC_KEY, publicKey);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            // cipher.init(Cipher.ENCRYPT_MODE, keySpec);

            // CipherOutputStream cipherOutputStream = new
            // CipherOutputStream(fileOutputStream, cipher);

            byte[] buf = new byte[117];
            byte[] encryptedData = null;
            int read;
            while ((read = fileInputStream.read(buf)) > 0) {
                encryptedData = cipher.doFinal(buf);
                fileOutputStream.write(encryptedData);
                // cipherOutputStream.write(buf);
            }

            fileInputStream.close();
            fileOutputStream.flush();
            // cipherOutputStream.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Used to do decryptFile the file
     *
     * @param srcPath  File path to be decrypted
     * @param destPath Decrypts the file in srcPath and creates a file in destPath
     * @return true if encryption success, false otherwise
     */
    public boolean decryptFile(String srcPath, String destPath) {

        try {

            FileInputStream fileInputStream = new FileInputStream(srcPath);
            FileOutputStream fileOutputStream = new FileOutputStream(destPath);

            // byte[] key = "12345678".getBytes();
            // SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);

            Cipher cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.PRIVATE_KEY, privateKey);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            // cipher.init(Cipher.DECRYPT_MODE, keySpec);

            // CipherOutputStream cipherOutputStream = new
            // CipherOutputStream(fileOutputStream, cipher);

            byte[] buf = new byte[128];
            byte[] decryptedData = null;
            int read;
            while ((read = fileInputStream.read(buf)) > 0) {
                decryptedData = cipher.doFinal(buf);
                fileOutputStream.write(decryptedData);
                // cipherOutputStream.write(buf);
            }

            fileInputStream.close();
            fileOutputStream.flush();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
在活动中我喜欢

RSAHelper rsaHelper = null;
        try {
            rsaHelper = new RSAHelper();
        } catch (Exception e) {
            e.printStackTrace();
        }
        String src = getExternalFilesDir("sdcard").getAbsolutePath() + "/mother.png";
        String dest = src.replace("mother","motherEnc");
        String decrypted = dest.replace("motherEnc","motherDec");

        rsaHelper.encryptFile(src, dest);
        rsaHelper.decryptFile(dest, decrypted);
但解密的
文件不是原始文件(表示已损坏)

当我在windows桌面上执行时,同样的代码工作

我做错什么了吗


提前感谢。

继续@zaph评论中开始的列表:

  • 您正在初始化密码两次,幸运的是使用相同的模式,因此这只是混淆,而不是错误的来源
  • 密码转换依赖于默认值,这是不可移植性、错误和/或混乱的常见原因。始终明确指定完整的密码转换,如
    Cipher.getInstance(“RSA/ECB/PKCS1PADDING”)
    Cipher.getInstance(“RSA/ECB/NOPADDING”)
  • 您错误地假设InputStream.read()在字节可用时总是返回一个完整的字节缓冲区。这可能是FileInputStream的当前实现实际工作的方式,但这只是运气。这种行为在任何时候都可以在没有警告的情况下改变。InputStream实现者只需要遵守InputStreamAPI契约,这就是您应该依赖的全部。您确实记录了实际读取的字节数,但随后您不会对其执行任何操作
  • 您正在刷新输出流,但没有关闭它。你应该把它关上

  • 你的错误是由数字5引起的。由于无法保证您的输入文件是117字节的精确倍数,因此最后一个块可能小于117字节。但是,然后加密完整的117字节块,其中的尾随字节只是上次读取的剩余字节。因此,解密后的文件将是117的倍数,并与原始长度匹配,尾随字节与前一块的尾随字节相同。

    继续@zaph注释中开始的列表:

  • 您正在初始化密码两次,幸运的是使用相同的模式,因此这只是混淆,而不是错误的来源
  • 密码转换依赖于默认值,这是不可移植性、错误和/或混乱的常见原因。始终明确指定完整的密码转换,如
    Cipher.getInstance(“RSA/ECB/PKCS1PADDING”)
    Cipher.getInstance(“RSA/ECB/NOPADDING”)
  • 您错误地假设InputStream.read()在字节可用时总是返回一个完整的字节缓冲区。这可能是FileInputStream的当前实现实际工作的方式,但这只是运气。这种行为在任何时候都可以在没有警告的情况下改变。InputStream实现者只需要遵守InputStreamAPI契约,这就是您应该依赖的全部。您确实记录了实际读取的字节数,但随后您不会对其执行任何操作
  • 您正在刷新输出流,但没有关闭它。你应该把它关上

  • 你的错误是由数字5引起的。由于无法保证您的输入文件是117字节的精确倍数,因此最后一个块可能小于117字节。但是,然后加密完整的117字节块,其中的尾随字节只是上次读取的剩余字节。因此,解密后的文件将是117的倍数,并与原始长度匹配,尾随字节与前一块的尾随字节相同。

    1。RSA不是为加密大数据而设计的,它只限于小于密钥大小的数据大小。对于1024个密钥大小,数据大小限制在128字节以下。数据通常使用对称算法(如AES)进行加密。2.为什么要使用RSA公钥/私钥加密?如果您确实需要公钥/私钥对,则需要使用混合加密,其中数据使用对称密钥加密,该密钥使用非对称加密(如RSA.1)加密。RSA不是为加密大数据而设计的,它只限于小于密钥大小的数据大小。对于1024个密钥大小,数据大小限制在128字节以下。数据通常使用对称算法(如AES)进行加密。2.为什么要使用RSA公钥/私钥加密?如果您确实需要公钥/私钥对,则需要使用混合加密,其中数据使用对称密钥加密,该密钥使用非对称加密(如RSA)加密。非常感谢。我理解这个问题。但我找不到解决办法。你能告诉我最好的加密和解密方法吗。如果可以的话,推荐任何图书馆。非常感谢詹姆斯。我理解这个问题。但我找不到解决办法。你能告诉我最好的加密和解密方法吗。建议任何图书馆(如有)。