【发布时间】:2016-12-26 16:17:59
【问题描述】:
我想使用 Arduino 加密文本并使用 Java 解密。我从this link 尝试了这段代码,但没有成功。
我正在使用这个Arduino library 对 Arduino 和 Java 端的 Java 加密扩展 (JCE) 框架进行加密。
这是 Arduino 代码:
#include <AESLib.h> //replace the ( with < to compile (forum posting issue)
#include <Base64.h>
void setup() {
Serial.begin(9600);
uint8_t key[] = {50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50};
//expressed in 16 unsigned in characters, be careful not to typecast this as a char in a decrypter
//16- 50's (uint8) is the way to express 16 2's in ASCII, the encryption matches to what will show up on <a href="http://aesencryption.net/" target="_blank" rel="nofollow">http://aesencryption.net/</a>
char data[] = "0123456789012345";
//The message to encrypt, 16 chars == 16 bytes, no padding needed as frame is 16 bytes
char encryptedData[100];
int *size;
Serial.print("Message:");
Serial.println(data);
aes128_enc_single(key, data);
Serial.print("encrypted:");
Serial.println(data);
int inputLen = sizeof(data);
int encodedLen = base64_enc_len(inputLen);
char encoded[encodedLen];
base64_encode(encoded, data, inputLen);
Serial.print("encrypted(base64):"); //used
Serial.println(encoded);
Serial.println("***********Decrypter************");
int input2Len = sizeof(encoded);
int decodedLen = base64_dec_len(encoded, input2Len);
char decoded[decodedLen];
base64_decode(decoded, encoded, input2Len);
Serial.print("encrypted (returned from Base64):");
Serial.println(decoded);
Serial.print("decrypted:");
Serial.println(decoded);
}
void loop() {
}
这是Java代码:
package main;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class ForTest {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
String message= "0123456789012345";//Message to encode
String key = "2222222222222222";
// 128 bit key -this key is processed as ASCII values
System.out.println("Processing 3.0 AES-128 ECB Encryption/Decryption Example");
System.out.println("++++++++++++++++++++++++++++++++");
System.out.println("Original Message: " + message);
System.out.println("Key: " + key);
System.out.println("key in bytes: "+key.getBytes("UTF-8"));
System.out.println("==========================");
//Encrypter
SecretKeySpec skeySpec_encode = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher_encode = Cipher.getInstance("AES/ECB/NoPadding");
// Cipher cipher_encode = Cipher.getInstance("AES/ECB/PKCS5PADDING"); //AES-CBC with IV encoding, ECB is used without the IV, example shown on <a href="http://aesencryption.net/" target="_blank" rel="nofollow">http://aesencryption.net/</a>
cipher_encode.init(Cipher.ENCRYPT_MODE, skeySpec_encode);
byte[] encrypted = cipher_encode.doFinal(message.getBytes());
System.out.println("Encrypted String (base 64): "
+ DatatypeConverter.printBase64Binary(encrypted));
//encode without padding: Base64.getEncoder().withoutPadding().encodeToString(encrypted));
//encode with padding: Base64.getEncoder().encodeToString(encrypted));
String base64_encrypted = DatatypeConverter.printBase64Binary(encrypted);
//Decrypter
SecretKeySpec skeySpec_decode = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher_decode = Cipher.getInstance("AES/ECB/NoPadding");
// Cipher cipher_decode = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher_decode.init(Cipher.DECRYPT_MODE, skeySpec_decode);
System.out.println("length: "+"Ouril+UTDF8htLzE".length());
byte[] decrypted_original = cipher_decode.doFinal(DatatypeConverter.parseBase64Binary("Ouril+UTDF8htLzEhiRj7wA="));
String decrypt_originalString = new String(decrypted_original);
System.out.println("Decrypted String: " + decrypt_originalString);
}
}
在 Java 中,当我尝试用 Arduino 解密编码的字符串时,我得到了这个:
Processing 3.0 AES-128 ECB Encryption/Decryption Example
++++++++++++++++++++++++++++++++
Original Message: 0123456789012345
Key: 2222222222222222
key in bytes: [B@2a139a55
==========================
Encrypted String (base 64): Ouril+UTDF8htLzEhiRj7w==
length: 16
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1016)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:960)
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 main.ForTest.main(ForTest.java:46)
有什么想法吗? 谢谢!
【问题讨论】:
-
您尝试base64解码和解密的字符串是
Ouril+UTDF8htLzEhiRj7wA=,在base64解码后是17个字节,后面有一个0字节。之前打印的字符串是Ouril+UTDF8htLzEhiRj7w==,除了尾随字节之外,它是相同的(在base 64解码之后),并且是正确的长度(16字节)。 -
但是为什么我在使用 arduino 和 Java 进行 base64 编码后没有得到相同的结果?使用 Arduino 我得到了:
Ouril+UTDF8htLzEhiRj7wA=,使用 Java 我得到了Ouril+UTDF8htLzEhiRj7w==,我该如何纠正呢?谢谢! -
Arduino 输出引入了一个额外的字节。我不熟悉 Arduino 语言本身,但快速浏览一下,它是 C/C++ 的一个子集。 C以其字符串“空终止”而闻名(即,为了指示具有任意长度的字符串的结尾,它添加了一个包含值
0x00的字节)。这可能就是这里发生的事情。 -
在您的 Java 代码中,您需要将输入的密文修剪到
0x00字节之前的字节。此外,如果输入的明文和密文不是 16 字节的精确倍数(AES 的块大小),并且ECB是最差的密码块模式(相当于 在大多数情况下不加密)。查看cipher block modes of operation 上的此 Wikipedia 条目并选择一个更好的选项(GCM 建议用于 AEAD 属性)。 -
您也可以从源头解决这个问题,并且只有 Base64 将密文的内容编码为 Arduino 中的空字节,但我不太了解这种语言是否有一个简单的这样做的方法。您可能只能在编码之前从
char[]中修剪最后一个字节。
标签: java encryption arduino cryptography aes