当前位置: 首页 > 知识库问答 >
问题:

使用RSA解密字符串会在开头返回额外的零

后星河
2023-03-14

我试图生成一个AES密钥,加密它,并使用RSA解密它。它有点工作,除了解密数据并用Base64编码后,我在实际字符串(Base64编码的AES密钥)之前得到一堆“A”字母。我猜这些是字节中的零。

“RSA/ECB/NoPadd”参数是强制性的。我做错了什么?我需要它来返回原始字符串/字节。

package szyfrator;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

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

import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.tools.bzip2.CBZip2OutputStream;

import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.sun.org.apache.xml.internal.security.utils.Base64;

public class Cryptography {

    private static byte[] aesKey;
    private static String base64AESKey;
    private static byte[] encryptedAESKey;
    private static String base64AESEncryptedKey;
    private static byte[] aesKeyTransformed;

    public static void main(String args[]){

        Cryptography.generateAESkey();
        Cryptography.encryptAESKey(new File("G:\\HASHBABYHASH\\public.txt"));
        Cryptography.decryptAESKey(new File("G:\\HASHBABYHASH\\private.txt"));

        System.out.println("String: " + Base64.encode(Cryptography.getAesKey()) + "\r\n");
        System.out.println("Encrypted string: " + Cryptography.getBase64EncryptedKey() + "\r\n");
        System.out.println("Decrypted String: " + Base64.encode(Cryptography.getAesKeyTransformed()) + "\r\n");

    }

    public static void generateAESkey(){

        try {
            KeyGenerator    keyGen = KeyGenerator.getInstance("AES");

            keyGen.init(256); 
            SecretKey secretKey = keyGen.generateKey();

            byte[] keyBytes = secretKey.getEncoded(); 
            base64AESKey = Base64.encode(keyBytes); 

            aesKey = keyBytes;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static void encryptAESKey(File publicKeyFile){

        try {       
            FileInputStream input = new FileInputStream(publicKeyFile);

            byte[] decoded = Base64.decode(IOUtils.toByteArray(input));     

            X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(decoded);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(publicSpec);   

            Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);  

            encryptedAESKey = cipher.doFinal(aesKey);
            base64AESEncryptedKey = Base64.encode(encryptedAESKey);

            input.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void decryptAESKey(File privateKeyFile){

        try {
            FileInputStream input = new FileInputStream(privateKeyFile);

            byte[] decoded = Base64.decode(IOUtils.toByteArray(input));

            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

            Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);  

            aesKeyTransformed = cipher.doFinal(encryptedAESKey);
            input.close();  
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果如下:

String: xVwH7Nbz84emVoH0J31sRHC+B669T9wCUVlTDhYgXiI=

Encrypted string: INTA8rx46hX6bZbDIl4iiWsUGO4ywCW0Aee1reqQ3wR5X7He5ztLHvyZoa0WZmUGYbYwprNGffRI
OVJFxczMHkxUfHU1WWCTzcfNylD+sWObIYrbyc13aZi9OL/r1GXuaGtkIgTJyqv0QPHfIri7iaH3
Lr/F4EIcyphJM3E2reQ=

Decrypted String: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxVwH7Nbz84emVoH0J31sRHC+
B669T9wCUVlTDhYgXiI=

共有1个答案

梁丘安晏
2023-03-14

在RSA中,一些数据被编码成一个大数字,并根据它进行计算NoPadding(unpadded或RSA)表示您对消息的正确编码负有全部责任。所有的计算都是针对大模数进行的(现在至少应该是2048位)。由于Java采用大端数,因此消息会自动编码为最低有效字节,但解密会以相同的模大小返回解码后的消息,因为它无法知道前导的零字节是否是有意的。

为了使这种计算正确和安全,有必要应用填充。老式的PKCS#1 v1.5填充现在不被认为是安全的,但它只有11字节的开销(只有2048/8-11=245字节可以用2048位的密钥加密)。较新的PKCS#1 v2.1填充(OAEP)被认为是安全的,应该在这里使用。如果使用SHA-1,它确实有42字节的开销。

“RSA/ECB/NoPadd”参数是强制性的。

这真的很糟糕,因为它非常不安全:哪些攻击可能针对原始/教科书RSA?

如果您不愿意简单地将密码字符串更改为Cipher.get实例("RSA/ECB/OAEPwith SHA-256AndMGF1Padd");,您将不得不自己删除前导零。问题当然是这种“零填充”模式是不明确的,如果明文以0x00字节开始,您将无法将其与填充字节区分开来,因此必须将其删除,从而破坏您的明文。如果明文是AES密钥,就像您的情况一样,有0.3%的可能性它以0x00字节开始,从而破坏密钥。您必须确保密钥实际上是正确的,如果它没有正确的长度,请用零字节填充。

以下是删除前导零字节的方法:

byte[] unpadZeros(byte[] in) {
    int i = 0;
    while(in[i] == 0) i++;
    return Arrays.copyOfRange(in, i, in.length);
}

如果您知道您正在解密AES密钥,则可能会使未加密密钥生成错误数据

byte[] unpadZerosToGetAesKey(byte[] in) {
    int i = 0;
    while(in[i] == 0) i++;
    int len = in.length - i;
    if (len <= 16) len = 16;
    else if (len <= 24) len = 24;
    else len = 32;
    return Arrays.copyOfRange(in, in.length - len, in.length);
}
 类似资料:
  • 我有一个公钥和一个私钥,还有一个字符串,我想要解密。 公钥的格式如下: 私钥的格式如下: 我要解密的字符串已经使用公钥加密,然后我需要使用私钥解密它。

  • 问题内容: 我正在尝试实施PKI。我想在Java中使用RSA而不使用弹性城堡来加密大字符串。我得到的问题是数据不得超过117个字节。我尝试寻找失败的解决方案。我是这种加密的新手。请提供一个大字符串作为示例来帮助我并进行解释。 问题答案: 一次不能使用超过128个字节的RSA加密解密。您必须拆分数据并在循环中进行处理,几乎可以随时将字节写入String / Array。如果您唯一的问题是数据大小,那

  • 我有这个密码 我将答案转换为json,但无法转换,因为开头的答案是,额外字符请参见示例 响应标头 HTTP/1.1 200 OK缓存控制:私有内容长度:232内容类型:应用程序/json;charset=utf-8服务器:Microsoft IIS/7.5 X-AspNet-Version:2.0.50727 X-Powered-By:ASP。NET访问控制允许来源:*访问控制允许方法:PUT、O

  • 我设置了Azure密钥库来检索RSA密钥进行加密。Azure发送给我一个KeyBundle类型的对象。此对象包含一个大小为2048的RSA类型的JsonWebKey。查看我的RSA密钥,它有两个方法,称为和。现在我正在尝试加密和解密一个简单的字符串,如下所示: 在System.Security.Cryptography.RSAImplementation.RSACNG.EncryptorDecry

  • 在我的android应用程序中,我正在实现RSA加密解密。 我们有这个适用于ios和android的应用程序。 每当ios用我的公钥加密消息时,都会在base64中发送加密文本,在android端,我会用私钥解密。 问题是,每当我解密数据时,它就会产生被垃圾填充包围的加密消息 如下所示: K������N�t�十、�08���我�二、�z� “test updated pub key”是消息。 我