如何使用密码解码字符串?

时间:2017-10-28 06:35:05

标签: java encryption base64 password-protection password-encryption

我有一个密码需要通过网络传输。所以对于安全方面,我已经从发送端编码并在接收端进行解码。

但我的朋友仍然可以在网络上破解密码,因为他知道我是如何编码密码字符串的。

这是我的代码

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中通过网络发送的相同字符串吗?

1 个答案:

答案 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用于从密码生成加密的比特流,然后用我们的明文进行异或。

总而言之,上面的示例适合生产使用,并且完全安全。