在我们的一个内部软件中,我们正在实施一个新的API端点,必须通过互联网访问外部资源,然后必须以某种方式保护它。
由于我们不允许将库用作OAuth
或公钥和私钥,因此我们选择javax.crypto AES
以这种方式在每个外部源中隐藏“自定义授权令牌”:
...
Key aesKey = new SecretKeySpec("API-KEY".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] applicationIdEncrypted = cipher.doFinal(applicationId.getBytes());
...
token
包含自定义applicationId
,以便在另一方识别谁正在联系该终端。
由于我们必须执行HTTP调用,因此我们将applicationIdEncrypted
转换为base64字符串
String base64Encoded = Base64.getEncoder().encodeToString(applicationIdEncrypted);
在另一边
我们正在获取标题并从base64
解码String base64Decoded = new String(Base64.getDecoder().decode(header));
但是在尝试执行上一次操作时
Key aesKey = new SecretKeySpec("API-KEY".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String headerDecoded = new String(cipher.doFinal(base64Decoded.getBytes())); //<- THIS
我们得到javax.crypto.BadPaddingException: Given final block not properly padded
两个base64Encoded
和base64Decoded
都有相同的值。
尝试在其中一端执行相同的操作(不使用HTTP通道)不会抛出异常 - 但是{{1}返回了不同的headerDecoded
}}
查找字节new String(cipher.doFinal(base64Decoded.getBytes()));
和applicationIdEncrypted
,它们略有不同:
applicationIdEncrypted
base64Decoded.getBytes()
base64Decoded.getBytes()
[-28, -103, 107, 70, -112, 121, 4, -14, -80, -114, -14, 92, -81, -13, -128, 97]
我读到可能从字节传递到字符串可能是信息丢失(可能?)但我无法弄清楚这种行为的原因,因为[-28, -103, 107, 70, 63, 121, 4, -14, -80, -114, -14, 92, -81, -13, -128, 97]
和base64Encoded
都具有SAME值案例和情景。
如何仅使用Java 1.7 base64Decoded
库来实现“自定义授权令牌”?
修改
javax.crypto
类似于"API-KEY"
答案 0 :(得分:1)
正如@James K Polk所说,我对String
转换进行了数千次混乱,所以我设法先使用更清晰的代码来获得更好的综合代码。
在客户端
Key aesKey = new SecretKeySpec("API-KEY".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] applicationIdEncrypted = cipher.doFinal(applicationId.getBytes());
byte[] base64Encoded = Base64.getEncoder().encode(applicationIdEncrypted);
String out = new String(base64Encoded);
其中out
是String
中唯一的一次转换,它是HTTP标头的有效负载。
在另一边
byte[] in = out.getBytes();
byte[] base64Decoded = Base64.getDecoder().decode(in);
Key aesKey = new SecretKeySpec("API-KEY".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, aesKey);
byte[] applicationIdDecrypted = cipher.doFinal(base64Decoded);
String applicationId= new String(applicationIdDecrypted);
我只有两次转换为String
:out
(标头的base64值)和applicationId
。
通过这种方式,我曾经拥有相同的applicationId
值。