我试图生成一个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=
在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);
}
userData.json:
我有一个公钥和一个私钥,还有一个字符串,我想要解密。 公钥的格式如下: 私钥的格式如下: 我要解密的字符串已经使用公钥加密,然后我需要使用私钥解密它。
问题内容: 我正在尝试实施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”是消息。 我