我有一个密码需要通过网络传输。所以对于安全方面,我已经从发送端编码并在接收端进行解码。
但我的朋友仍然可以在网络上破解密码,因为他知道我是如何编码密码字符串的。
这是我的代码
package org;
import java.util.Base64;
public class EncodingString {
public static void main(String[] args){
String str = "I'm Encoding then decoding";
byte[] bytesEncoded = Base64.getEncoder().encode(str.getBytes());
System.out.println(bytesEncoded);
String EncodedPassword = new String(bytesEncoded);
System.out.println("ecncoded value is " + EncodedPassword);
byte[] valueDecoded= Base64.getDecoder().decode(bytesEncoded);
System.out.println(valueDecoded);
String DecodedPassword = new String(valueDecoded);
System.out.println("Decoded value is " + DecodedPassword);
}
}
我想知道,有可能我可以在我的编码字符串上加上某种密码,这样我可以使用相同的密码来解码在java中通过网络发送的相同字符串吗?
答案 0 :(得分:2)
首先了解编码和加密之间的区别可能会有所帮助。编码描述了用于表示信息的协议。您已经使用了base64,它将二进制信息编码为ASCII字符的子集。
加密就是您想要的。加密算法使用密钥(您的“密码”,具有额外要求)来操纵数据,使得在没有密钥的情况下检索数据在计算上是困难的(读取:几乎不可能)。
请看下面的摘录,演示如何在GCM模式下使用AES来安全地加密某些数据:
// The plaintext to encrypt, and the password we want to use.
String plaintext = "Hello, World!";
String password = "WizardsAreCool";
// Parameters for PBKDF2/AES. Using a higher iteration count
// is better in production.
int iterationCount = 25000;
int keySize = 128;
int tagSize = 128;
int saltSize = 16;
int nonceSize = 12;
// We generate a random salt for PBKDF2.
SecureRandom rng = new SecureRandom();
byte[] salt = new byte[saltSize];
rng.nextBytes(salt);
// We derive a 128-bit key using PBKDF2 from the password,
// as AES-128 expects a 128-bit key. We also use SHA256 instead
// of SHA1 for the underlying hash.
PBEKeySpec pwSpec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, keySize);
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] key = keyFac.generateSecret(pwSpec).getEncoded();
// We convert the plaintext to binary and generate a 12-byte nonce for
// GCM mode.
byte[] rawData = plaintext.getBytes(StandardCharsets.UTF_8);
byte[] nonce = new byte[nonceSize];
rng.nextBytes(nonce);
// We define the cipher.
Cipher aesGcm = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmSpec = new GCMParameterSpec(tagSize, nonce);
aesGcm.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), gcmSpec);
// We get the resulting ciphertext.
byte[] encResult = aesGcm.doFinal(rawData);
// We produce the final result by prepending the PBKDF2 salt and
// the nonce.
byte[] result = new byte[saltSize + nonceSize + encResult.length];
System.arraycopy(salt, 0, result, 0, saltSize);
System.arraycopy(nonce, 0, result, saltSize, nonceSize);
System.arraycopy(encResult, 0, result, saltSize + nonceSize, encResult.length);
// Print the result as base64.
byte[] b64Result = Base64.getEncoder().encode(result);
System.out.println(new String(b64Result));
// Sample Output
// C100zs91Ku/TbQw4Mgw7e95didsA1Vj5oHGeMitohnRaUGIB08+T6uESro4P2Gf7q/7moMbWTTNT
与原始代码相比,上面的代码中有很多内容,所以我会尽力解释。我们使用的加密算法AES需要一个长度为128,192或256位的密钥。由于法律原因,Java禁止使用密钥大小不是128位的AES,因此我们不得不在这里使用128位密钥。
因为我们想要使用的密码(“WizardsAreCool”)长度不是128位(实际上是14个UTF8字符,所以112位),我们使用PBKDF2,它是密钥派生函数 ,从我们的密码中获取一个128位长的密钥(因此keySize
为128)。
PBKDF2在这里采用了一些参数,包括密码字符串,盐(当使用PBKDF2作为密钥派生函数时,这并不是那么重要,但我们仍然应用良好的做法并使其随机化,如我们所应),和迭代计数,它确定将基础哈希应用于密码的次数。
AES也需要一些参数。最重要的是关键。它也需要一个随机数(因为我们处于GCM模式),它也应该是随机的。 nonce用于从密码生成加密的比特流,然后用我们的明文进行异或。
总而言之,上面的示例适合生产使用,并且完全安全。