gpt4 book ai didi

java - JAVA AES256加密/解密java.lang.NullPointerException + javax.crypto.BadPaddingExceptions

转载 作者:行者123 更新时间:2023-12-01 10:52:14 28 4
gpt4 key购买 nike

因此,我一直在设计自己的聊天程序时遇到一个非常烦人的问题。客户端以AES256格式加密消息,将它们作为字符串发送到服务器,然后服务器以以下形式将其重新分发给客户端:

<encrypted username> encrypted message


加密和解密消息是客户端的工作。从服务器返回的字符串与发送的字符串匹配。

使用本地定义的加密字符串时,ENCRYPTOR和DECRYPTOR可以正常工作。将未在同一实例中加密的加密消息放入DECRYPTOR中会产生空指针异常,BadPadding异常或其他奇怪的错误。

聊天系统工作正常,但是当需要解密消息时会出现问题

因此,我弄乱了代码,并尝试了许多变通办法以查看数据是否会再次解密。我最终尝试了多种解密方法,以查看其他方法是否可行,但无济于事。同样的问题。

 int port=1234;
String host="localhost";
try
{
socket=new Socket(host,port);
userip=new BufferedReader(new InputStreamReader(System.in));
output=new PrintStream(socket.getOutputStream());
input=new BufferedReader(new InputStreamReader(socket.getInputStream()));
// AES256 encryptedmessage = new AES256();
}
catch(Exception e)
{
System.err.println("Couldn't connect. "+host);
}
if(socket!=null)
{
try
{
//AES256 message = new AES256();
String encrypted = "";
new Thread(new Client()).start();
while(!flag)
{
encrypted = Global.encryptor.encrypt(userip.readLine());
//encrypted = message.encrypt(userip.readLine());
output.println(encrypted);
System.out.println(encrypted);
//NOT NECESSARY ^^^
}
output.close();
input.close();
socket.close();
}


将输入发送到服务器的部分是

output.println(encrypted);


其中,加密是通过加密方法放入的字符串
在AES256.java中
(我尝试在自己的文件中声明一个AES256对象,以避免出现空指针错误/其他反复发生的错误。它的工作原理完全相同,并且会导致相同的错误。)

客户端正确接收用户的输入,对其进行加密,然后将其发送到服务器。

SERVER通过以下代码接收加密的用户名和用户消息:

            public void run()
{
//AES256 X = new AES256();
String msg;
String username;
try
{
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output = new PrintStream(socket.getOutputStream());
output.println("Enter your alias: ");
username = input.readLine();
//THIS IS IMPORTANT.
output.println("CONNECTION ESTABLISHED");
output.println(username + ": CONNECTED.");
output.println("To disconnect, enter $$");
output.println("END UNENC");
for (int i = 0; i <= 9; i++)
if (th[i] != null && th[i] != this)
th[i].output.println("------------A new user connected: " + username);
while (true)
{
msg = input.readLine();
if (msg.startsWith("$$"))
break;
for (int i = 0; i <= 9; i++)
if (th[i] != null){
th[i].output.println("<" + username + "> " + msg);
}
}


这里的相关代码是

for (int i = 0; i <= 9; i++)
if (th[i] != null){
th[i].output.println("<" + username + "> " + msg);
}
}


上面的代码接收来自客户端的用户名和消息,并将其发送给所有连接的用户。用户名和消息仍然被加密。

此时,客户会收到以下性质的东西:

<nf8q3nfqlidcnalkm2> djiami2j389danfill23nlfuinvavv34


用户名和消息在字符方面与最初发送到服务器的完全相同。但是,当我尝试解密这两件事时,就会出现错误(主要是空指针错误)。

此信息通过以下代码在客户端文件中返回给客户端:

public void run()
{
String msg;
String unencrypt = "";
String line = "";
String username = "";
String message = "";
int index1 = 0;
int index2 = 0;

try
{
while((msg=input.readLine())!=null)
{
// d.SetMessage(msg);
// String original = msg;
// byte[] utf8Bytes = original.getBytes("UTF-8");
if(!msg.contains("<")){
System.out.println(msg);

}
else if(msg.contains("<"))
{
username = msg.substring(1, msg.indexOf(">"));
System.out.println("USERNAME:"+username);
message = msg.substring(msg.indexOf(">")+2,msg.length());
System.out.println("MESSAGE:"+message);
index1 = line.indexOf('<');
index2 = line.indexOf('>');
unencrypt = Global.encryptor.decrypt(username);
//System.out.println("<" + d.decrypt(d.GetMessage() + ">"));
}
}
flag=true;
}
catch(IOException e)
{
System.err.println("IOException" + e);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


您会注意到有很多未使用的,多余的或未完成的代码用于处理工作,但这仅仅是由于我尝试了千种不同的处理方法。与所有其他实例一样,此特定实例中的错误在客户端尝试解密从服务器返回的字符串时出现。

请记住,当字符串直接从加密器传回到同一实例中的解密器时,加密器和解密器可以完美地工作。

导致所有问题的主要原因是,试图以任何方式解密来自服务器的此字符串。此方法只是以下方法之一:

unencrypt = Global.encryptor.decrypt(username);


每当使用服务器上的字符串运行此解密器时,我们来看一下它带来的错误:

javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at Messenger.AES256.decrypt(AES256.java:84)
at Messenger.Client.run(Client.java:106)
at java.lang.Thread.run(Unknown Source)
java.lang.NullPointerException
at java.lang.String.<init>(Unknown Source)
at Messenger.AES256.decrypt(AES256.java:91)
at Messenger.Client.run(Client.java:106)
at java.lang.Thread.run(Unknown Source)


我对如何解决这个问题一无所知。这是即将发挥作用的AES256东西:

ENCRYPTOR(发送到服务器的内容)

  public String encrypt(String plainText) throws Exception {   

//get salt
salt = generateSalt();
byte[] saltBytes = salt.getBytes("UTF-8");

// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
pswdIterations,
keySize
);

SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

//encrypt the message
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return new Base64().encodeAsString(encryptedTextBytes);
}




DECRYPTOR(在发送给客户端的字符串上运行的内容)

 @SuppressWarnings("static-access")
public String decrypt(String encryptedText) throws Exception {

byte[] saltBytes = salt.getBytes("UTF-8");
byte[] encryptedTextBytes = new Base64().decodeBase64(encryptedText);

// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
pswdIterations,
keySize
);

SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

// Decrypt the message
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));


byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}

return new String(decryptedTextBytes);
}


我的信念是,当字符串发送到服务器并返回时,有关字符串的内容会发生变化。或者,AES256类需要在对字符串进行加密后记住一些有关字符串的信息。我不确定。

有人可以给我一些关于这件事的见解吗?我感觉它已经接近工作了,但是一旦将这些字符串发送回客户端,我就无法解密。

编辑:

            final protected static char[] hexArray =     "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);}


我正在尝试将ivBytes和salt转换为十六进制,以便可以将它们发送到服务器并返回,然后再次获取需要解密的内容。

当我尝试打印此新的十六进制时,我得到:

HEXADECIMAL IV BYTES: ?T???/0??q"?H


编辑#2:

我已经成功地将ivBytes []和saltBytes []转换为十六进制格式。我正在以...的形式将输入发送到服务器...

HexIvBytes + " " + HexSaltBytes + " " + EncryptedMessage


这是输出示例:

testing
HEXADECIMAL IV BYTES: 70FDE9D7D1A0E2AAD92A95E113186067
IV BYTES: [B@2aafb23c
HEXADECIMAL SALT BYTES: 71C385C387C2ACC2BDC3B2CB9C1BC3926F63370749C3B4C2BD04E280B9C2A90E
SALT BYTES: [B@2b80d80f
ENCRYPTED MESSAGE:eYgv/GxKP3oG3SbbnflTyw==
IVBYTES:[B@2aafb23c
<6C5D1C71F8C775C363C914982C617B11 C386C3A5C3A4C3AE1942C5BE565268175C5A7354C39F6F15C5A1C2A7 NtDi9/P696DgTezN7T0ZVg==> 70FDE9D7D1A0E2AAD92A95E113186067 71C385C387C2ACC2BDC3B2CB9C1BC3926F63370749C3B4C2BD04E280B9C2A90E eYgv/GxKP3oG3SbbnflTyw==


因此,我现在尝试在客户端解密这些内容。这就是我正在使用的:

if(msg.contains("<"))
{
username = msg.substring(1, msg.indexOf(">"));
usernameivHex = username.substring(0, username.indexOf(" "));
saltHex = username.substring(username.indexOf(" "), username.indexOf("|"));
encryptedUsername = username.substring(username.indexOf("|"),username.indexOf(">"));

d.setivBytes(hexStringToByteArray(usernameivHex));
d.setSaltBytes(hexStringToByteArray(saltHex));
System.out.println("DECRYPYTED USERNAME: " + d.decrypt(encryptedUsername));

}
}


我在此行中遇到了很多错误:

            encryptedUsername = username.substring(username.indexOf("|"),username.indexOf(">"));

java.lang.StringIndexOutOfBoundsException: String index out of range: -100
at java.lang.String.substring(Unknown Source)
at Messenger.Client.run(Client.java:155)
at java.lang.Thread.run(Unknown Source)


编辑#3:

成功!使用传输的IvBytes和SaltBytes,我能够在客户端成功解密字符串。

最佳答案

您需要使用相同的盐,而不仅仅是相同的密码。密码和盐确定密钥种子的值-PBKDF2的输出。这反过来又是密钥的输入材料(有时只是使用密钥种子中正确数量的字节)。

如果密钥无效,则很可能会出现填充错误。如果您要确定输入错误的盐/密码会出错,则可能要包含一个身份验证标签(例如,使用HMAC生成)。

发送盐的最简单方法是在编码之前简单地将其前缀为密文。如果要分隔盐和密文,可以将它们作为JSON string : value对发送

"salt"=<base64>
"ciphertext"=<base64>




IV也一样。

关于java - JAVA AES256加密/解密java.lang.NullPointerException + javax.crypto.BadPaddingExceptions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33795543/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com