[英]Issue when using AES 128 using JDK 7
我有一个从 Mainframe_JCL 触发的独立 Java 程序。 Java 程序有一个代码来加密和解密一个字符串。
当我在本地运行程序时。 加密后,当我解密时,该值是正确的(我得到了我为加密提供的字符串)。
但是当它通过 JCL 在大型机上运行时执行这个.. 我得到了奇怪的解密值.. 有点垃圾。
不知道是什么问题。 任何帮助,将不胜感激。
我们使用以下 JDK:IBM SDK for z/OS,Java 技术版,版本 7
以下是用于加密和解密的方法:
public static String encrypt(String text) throws UnsupportedEncodingException {
byte iv[] = new byte[16];
byte[] encrypted = null;
BASE64Encoder enc = new BASE64Encoder();
try {
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, getKeySpec(), ivspec);
encrypted = cipher.doFinal(text.getBytes());
} catch (Exception ex) {
ex.printStackTrace();
}
return URLEncoder.encode(enc.encode(iv)+enc.encode(encrypted), "UTF-8");
}
public static String decrypt(String text) {
byte iv[] = new byte[16];
String decrypted = "";
byte[] splitText = null;
byte[] textToDecrypt = null;
BASE64Decoder dec = new BASE64Decoder();
try {
text = URLDecoder.decode(text, "UTF-8");
text = text.replaceAll(" ", "+");
splitText = dec.decodeBuffer(text);
splitText.toString();
for(int i=0;i<16;i++){
iv[i]=splitText[i];
}
textToDecrypt = new byte[splitText.length - 16];
for(int i=16;i<splitText.length;i++){
textToDecrypt[i-16]=splitText[i];
}
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, getKeySpec(), ivspec);
decrypted = new String(cipher.doFinal(textToDecrypt));
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}
return decrypted;
}
static SecretKeySpec spec = null;
public static SecretKeySpec getKeySpec() throws IOException,
NoSuchAlgorithmException {
if (spec == null) {
String keyFile = "aes_key.key";
spec = null;
InputStream fis = null;
fis = Config.class.getClassLoader().getResourceAsStream(keyFile);
byte[] rawkey = new byte[16];
fis.read(rawkey);
fis.close();
spec = new SecretKeySpec(rawkey, "AES");
}
return spec;
}
你没有提供足够的信息来运行你的代码(所以我不会修复),但我看到两件事可能会破坏结果:
toBytes
和new String
定义字符编码; 目前您可能有两个不同的平台字符集来满足。 最后,URL 编码 base 64 可能不是很有效,你最好只用URL 安全对应物替换+
和/
字符。
所以我有一个谜题:
package nl.owlstead.stackoverflow;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public final class VeryStaticStringEncryption {
private static final String KEY_FILE = "aes_key.key";
private static final SecretKey AES_KEY = retrieveSecretKey(KEY_FILE);
private VeryStaticStringEncryption() {
// avoid instantiation
}
public static String encrypt(final String text) {
try {
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final int n = cipher.getBlockSize();
final SecureRandom random = new SecureRandom();
final byte[] iv = new byte[n];
random.nextBytes(iv);
final IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, AES_KEY, ivspec);
final byte[] plaintext = text.getBytes(UTF_8);
byte[] ciphertext = Arrays.copyOf(iv,
n + cipher.getOutputSize(plaintext.length));
final int ciphertextSize = cipher.doFinal(
plaintext, 0, plaintext.length,
ciphertext, n);
// output size may be bigger, but not likely
if (n + ciphertextSize < ciphertext.length) {
ciphertext = Arrays.copyOf(ciphertext, n + ciphertextSize);
}
return Base64.getUrlEncoder().encodeToString(ciphertext);
} catch (final GeneralSecurityException e) {
throw new IllegalStateException("Could not encrypt string", e);
}
}
public static String decrypt(final String text) {
try {
// throws IllegalArgumentException if decoding fails
final byte[] ciphertext = Base64.getUrlDecoder().decode(text);
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final int n = cipher.getBlockSize();
// CBC specific
if (ciphertext.length < n + n || ciphertext.length % n != 0) {
throw new IllegalArgumentException("Ciphertext has incorrect size");
}
final IvParameterSpec ivspec = new IvParameterSpec(ciphertext, 0, n);
cipher.init(Cipher.DECRYPT_MODE, AES_KEY, ivspec);
final byte[] plaintext = cipher.doFinal(ciphertext, n, ciphertext.length - n);
return new String(plaintext, UTF_8);
} catch (final GeneralSecurityException e) {
throw new IllegalStateException("Could not encrypt string", e);
}
}
public static SecretKey retrieveSecretKey(final String keyResource) {
try (final InputStream fis = VeryStaticStringEncryption.class.getResourceAsStream(keyResource)) {
final byte[] rawkey = new byte[16];
for (int i = 0; i < 16; i++) {
final int b = fis.read();
if (b == -1) {
throw new IOException("Key is not 16 bytes");
}
rawkey[i] = (byte) b;
}
if (fis.read() != -1) {
throw new IOException("Key is not 16 bytes");
}
return new SecretKeySpec(rawkey, "AES");
} catch (final IOException e) {
// e may contain confidential information
throw new IllegalStateException("AES key resource not available");
}
}
public static void main(String[] args) {
String ct = encrypt("owlstead");
System.out.println(ct);
String pt = decrypt(ct);
System.out.println(pt);
}
}
请注意,我使用了包本地资源,因为我不想弄乱我的 SO 项目。
重要说明:如果可能存在中间人攻击,CBC 加密对于传输模式加密是不安全的。 如果需要,重构为 GCM 模式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.