3 回答
TA贡献1993条经验 获得超5个赞
我建议你使用java.util.Base64解码。以下结果正确。我还建议使用修剪功能return originalString,看看是否有效。
public class Decrypt {
public static void main(String[] args) {
try
{
String data = "aK7+UX24ttBgfTnAndz9aQ==" ;
String key = "1234567812345678";
String iv = "1234567812345678";
Decoder decoder = Base64.getDecoder();
byte[] encrypted1 = decoder.decode(data);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
System.out.println(originalString.trim());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
TA贡献1793条经验 获得超6个赞
控制器部分生成 RSA 密钥(公共和私有)
package com.secure.encryption.decryption.controller;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.secure.encryption.decryption.rsa.keystore.KeyStore;
import com.secure.encryption.decryption.rsa.service.RSAKeyPairGenerator;
import com.secure.encryption.decryption.util.AesUtil;
@RestController
public class EncryptDecryptController {
@Autowired
RSAKeyPairGenerator rsa;
@Autowired
KeyStore keystore;
@CrossOrigin
@GetMapping(value = "get/rsa/public")
public Map<String, Object> generateRSA_PUBLIC_PRIVATE_KEY()
{
Map<String, Object> response = new HashMap<>();
/**
* Below function creates rsa public & private key
* While this api only share PUBLICKEY
* Whereas PRIVATEKEY is stored in bean/model
*/
String public_KEY = null;
public_KEY = rsa.KeyPairGenerator();
response.put("public", public_KEY);
return response;
}
@CrossOrigin
@PostMapping(value = "/decrypt/AES_encyptedKEY/with/RSA_privateKEY/decryptdata/with/aes")
public Map<String, Object> decrypt(@RequestBody Map<String, Object> req) throws UnsupportedEncodingException
{
/**
* First decrypt AES-Key which is encrypted with RSA Public Key
* Use RSA privateKey for decryption
*/
String Decrypted_AES_Key = rsa.decrypt(req.get("phrase").toString(),keystore.getPrivateKey());
byte[] decoded = Base64.getDecoder().decode(req.get("data").toString());
String encryptedAES_Data = new String(decoded, StandardCharsets.UTF_8);
/**
* Decode data to base 64
* Use AES key to decrypt the data
*/
AesUtil aesUtil = new AesUtil(128, 1000);
String decryptedAES_Data = aesUtil.decrypt(
req.get("salt").toString(),
req.get("iv").toString(),
Decrypted_AES_Key,
encryptedAES_Data);
/**
* Map actual data as response
*/
req.put("data", decryptedAES_Data);
return req;
}
@CrossOrigin
@GetMapping(value = "/decryptfrom/backend/aes/plain/decrypt/frontend")
public Map<String, Object> sendAESencryptedData()
{
/**
* Generate random key
* Encrypt data using same
* pass key to UI
* Decrypt using same key, iv and salt
*/
Map<String, Object> response = new HashMap<>();
int i = (int) (new Date().getTime()/1000);
//String iv = generateIv().toString();
AesUtil aesUtil = new AesUtil(128, 1000);
String phrase = String.valueOf(i);//"my secret key 123";
//String salt = new String(generateSalt(32));
String iv = "bb6a69ace7a11a38fba164238e000c7c";
String salt = "6c3674b6469467ab0b9f2b57ce36e78d";
String encryptedAES_Data =
Base64.getEncoder().encodeToString(
aesUtil.encrypt(
salt,
iv,
phrase,
"ganesha")
);
response.put("data", encryptedAES_Data);
response.put("salt", salt);
response.put("iv", iv);
response.put("key", phrase);
return response;
}
/*
public IvParameterSpec generateIv() {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
private byte[] generateSalt(int size) {
try {
byte[] salt = new byte[size];
SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
rand.nextBytes(salt);
return salt;
} catch (Exception e) {
System.err.println(e);
}
return null;
}
*/
}
生成 RSA 随机密钥的服务
package com.secure.encryption.decryption.rsa.service;
public interface RSAKeyPairGenerator {
public String KeyPairGenerator();
public byte[] encrypt(String data, String publicKey);
public String decrypt(String data, String base64PrivateKey);
}
实现类
package com.secure.encryption.decryption.rsa.service;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.secure.encryption.decryption.rsa.keystore.KeyStore;
@Service
public class RSAKeyPairGeneratorImpl implements RSAKeyPairGenerator{
@Autowired
KeyStore keystore;
@Override
public String KeyPairGenerator() {
Map<String, Object> keypair = new HashMap<String, Object>();
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair pair = keyGen.generateKeyPair();
final String privatestring = Base64.getEncoder().encodeToString(pair.getPrivate().getEncoded());
final String publicstring = Base64.getEncoder().encodeToString(pair.getPublic().getEncoded());
keystore.setPrivateKey(privatestring);
return publicstring;
} catch (Exception e) {
System.err.println(e);
}
return null;
}
private static PublicKey getPublicKey(String base64PublicKey){
PublicKey publicKey = null;
try{
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(base64PublicKey.getBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return publicKey;
}
private static PrivateKey getPrivateKey(String base64PrivateKey){
PrivateKey privateKey = null;
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64PrivateKey.getBytes()));
KeyFactory keyFactory = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
try {
privateKey = keyFactory.generatePrivate(keySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return privateKey;
}
public byte[] encrypt(String data, String publicKey) {//throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
try {
//AES/CBC/PKCS5Padding
//RSA/ECB/PKCS1Padding
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
return cipher.doFinal(data.getBytes());
} catch (Exception e) {
System.err.println(e);
}
return null;
}
private static String decrypt(byte[] data, PrivateKey privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(data));
}
public String decrypt(String data, String base64PrivateKey) {//throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
try {
return decrypt(Base64.getDecoder().decode(data.getBytes()), getPrivateKey(base64PrivateKey));
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
AesUtil 类
package com.secure.encryption.decryption.util;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.tomcat.util.codec.binary.Base64;
public class AesUtil {
private final int keySize;
private final int iterationCount;
private final Cipher cipher;
public AesUtil(int keySize, int iterationCount) {
this.keySize = keySize;
this.iterationCount = iterationCount;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}
catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw fail(e);
}
}
public byte[] encrypt(String salt, String iv, String passphrase, String plaintext) {
try {
SecretKey key = generateKey(salt, passphrase);
byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, key, iv, plaintext.getBytes("UTF-8"));
System.out.println(encrypted);
return encrypted;//Base64.getEncoder().encodeToString(encrypted);
//String s = Base64.getEncoder().encodeToString(encrypted);
}
catch (UnsupportedEncodingException e) {
throw fail(e);
}
}
public String decrypt(String salt, String iv, String passphrase, String ciphertext) {
try {
SecretKey key = generateKey(salt, passphrase);
byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, base64(ciphertext));
return new String(decrypted, "UTF-8");
}
catch (UnsupportedEncodingException e) {
return null;
}catch (Exception e){
return null;
}
}
private byte[] doFinal(int encryptMode, SecretKey key, String iv, byte[] bytes) {
try {
cipher.init(encryptMode, key, new IvParameterSpec(hex(iv)));
return cipher.doFinal(bytes);
}
catch (InvalidKeyException
| InvalidAlgorithmParameterException
| IllegalBlockSizeException
| BadPaddingException e) {
return null;
}
}
private SecretKey generateKey(String salt, String passphrase) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), hex(salt), iterationCount, keySize);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
return key;
}
catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
return null;
}
}
public static byte[] base64(String str) {
return Base64.decodeBase64(str);
}
public static byte[] hex(String str) {
try {
return Hex.decodeHex(str.toCharArray());
}
catch (DecoderException e) {
throw new IllegalStateException(e);
}
}
private IllegalStateException fail(Exception e) {
return null;
}
}
遵循的步骤
使用 RSA 密钥
生成随机 AES(密钥、iv、盐)- 使用 crypto.js
使用 AES 并加密易受攻击的数据
使用RSA公钥加密AES密钥
通过网络发送加密数据和密钥
服务使用 AES 数据解密密钥
使用AES密钥解密数据
将数据发送回前端
Html页面供参考
<!DOCTYPE html>
<html>
<body>
<script src="jquery.min.js"></script>
<script src="jsencrypt.min.js"></script>
<script type="text/javascript" src="crypto-js.min.js"></script>
<script type="text/javascript" src="aes.js"></script>
<script type="text/javascript">
const payloadsample = {
"addressLine1": "301,Kamala Mills Compound",
"addressLine2": "Gr Flr, Tulsi Pipe Rd, Lower Parel ",
"addressLine4": "Mumbai, Maharashtra",
"zipcode": 400071
};
/**
Step 1 ) - get data
**/
/**
Step 2 ) - get RSA pub Key
**/
function hybridEncryption()
{
$.ajax({
type: 'GET',//post
url: 'http://localhost:1818/get/rsa/public',
success: function(res) {
let RSAEncrypt = new JSEncrypt();
RSAEncrypt.setPublicKey(res.public);//set RSA public key
const key = Math.random().toString(36).slice(2);//Generate random AES key
console.log("key ", key);
var iv = CryptoJS.lib.WordArray.random(128/8).toString(CryptoJS.enc.Hex);
var salt = CryptoJS.lib.WordArray.random(128/8).toString(CryptoJS.enc.Hex);
var aesUtil = new AesUtil(128, 1000);
debugger
console.log(key)
var data = JSON.stringify({ payloadsample });
var ciphertext = aesUtil.encrypt(salt, iv, key, data);
/**
Step 3 ) - generate key
**/
senData(RSAEncrypt, iv, salt, key, btoa(ciphertext))
},
error:function(e) {
console.error(e);
},
contentType: "application/json",
dataType: 'json'
});
}
function senData(RSAEncrypt, iv, salt, key, base64Content)
{
const payload = {
"phrase":RSAEncrypt.encrypt(key),//encrypt with RSA
"data":base64Content,
"iv":iv,
"salt":salt
}
console.log("sending : ", payload);
$.ajax({
type: 'POST',
url: 'http://localhost:1818/decrypt/AES_encyptedKEY/with/RSA_privateKEY/decryptdata/with/aes',
data: JSON.stringify (payload), // or JSON.stringify ({name: 'jonas'}),
success: function(data) {
console.log(data);
},
error:function(e) {
console.error(e);
},
contentType: "application/json",
dataType: 'json'
});
}
hybridEncryption();
/**
* Incase of Backend encryption to Front end Decryption
* decryptBE() - will get AES encrypted data with associated data
* */
function decryptBE()
{
$.ajax({
type: 'GET',//post
url: 'http://localhost:1818/decryptfrom/backend/aes/plain/decrypt/frontend',
success: function(res) {
debugger
var aesUtil = new AesUtil(128, 1000);
var ciphertext = aesUtil.decrypt(res.salt, res.iv, res.key, res.data);
console.log(ciphertext);
},
error:function(e) {
console.error(e);
},
contentType: "application/json",
dataType: 'json'
});
}
</script>
</body>
</html>
这是一个使用参考的工作示例
使用的其他库是 aes.js
var AesUtil = function(keySize, iterationCount) {
this.keySize = keySize / 32;
this.iterationCount = iterationCount;
};
AesUtil.prototype.generateKey = function(salt, passPhrase) {
var key = CryptoJS.PBKDF2(
passPhrase,
CryptoJS.enc.Hex.parse(salt),
{ keySize: this.keySize, iterations: this.iterationCount });
return key;
}
AesUtil.prototype.encrypt = function(salt, iv, passPhrase, plainText) {
var key = this.generateKey(salt, passPhrase);
var encrypted = CryptoJS.AES.encrypt(
plainText,
key,
{ iv: CryptoJS.enc.Hex.parse(iv) });
return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}
AesUtil.prototype.decrypt = function(salt, iv, passPhrase, cipherText) {
var key = this.generateKey(salt, passPhrase);
var cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext: CryptoJS.enc.Base64.parse(cipherText)
});
var decrypted = CryptoJS.AES.decrypt(
cipherParams,
key,
{ iv: CryptoJS.enc.Hex.parse(iv) });
return decrypted.toString(CryptoJS.enc.Utf8);
}
其余的是
JSEncrypt v2.3.1 https://npmcdn.com/jsencrypt@2.3.1/LICENSE.txt
最后是 crypto-js.min.js
谢谢,我希望这会有用
TA贡献1836条经验 获得超4个赞
当您在 JS 中填充时,zeros
您无法使用 解密NoPadding
,解决方案是对数组或字符串进行操作
修剪数组
int i = original .length - 1; while (i >= 0 && original [i] == 0) { --i; } return new String(Arrays.copyOf(original , i + 1));
修剪字符串
return new String(original).trim();
手动删除
zero
值return new String(original).replace("\0", "");
ZeroPAdding
或者,因为Java 中似乎没有实现 ( Cipher Documentation
),建议使用CryptoJS.pad.Pkcs
添加回答
举报