【发布时间】:2023-03-27 22:28:01
【问题描述】:
我尝试移植 Google 的代码以为其验证码 (https://github.com/google/recaptcha-java/blob/master/appengine/src/main/java/com/google/recaptcha/STokenUtils.java) 生成安全令牌,但收效甚微:
原始实用程序具有以下内容:
private static final String CIPHER_INSTANCE_NAME = "AES/ECB/PKCS5Padding";
private static String encryptAes(String input, String siteSecret) {
try {
SecretKeySpec secretKey = getKey(siteSecret);
Cipher cipher = Cipher.getInstance(CIPHER_INSTANCE_NAME);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return BaseEncoding.base64Url().omitPadding().encode(cipher.doFinal(input.getBytes("UTF-8")));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static SecretKeySpec getKey(String siteSecret){
try {
byte[] key = siteSecret.getBytes("UTF-8");
key = Arrays.copyOf(MessageDigest.getInstance("SHA").digest(key), 16);
return new SecretKeySpec(key, "AES");
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
public static void main(String [] args) throws Exception {
//Hard coded the following to get a repeatable result
String siteSecret = "12345678";
String jsonToken = "{'session_id':'abf52ca5-9d87-4061-b109-334abb7e637a','ts_ms':1445705791480}";
System.out.println(" json token: " + jsonToken);
System.out.println(" siteSecret: " + siteSecret);
System.out.println(" Encrypted stoken: " + encryptAes(jsonToken, siteSecret));
鉴于我硬编码的值,我将Irez-rWkCEqnsiRLWfol0IXQu1JPs3qL_G_9HfUViMG9u4XhffHqAyju6SRvMhFS86czHX9s1tbzd6B15r1vmY6s5S8odXT-ZE9A-y1lHns" 作为我的加密令牌返回。
我的 Java 和加密技能有点生疏,而且 C# 中并不总是有直接的类似物。我试图将encrypeAes() 和getKey() 与以下内容合并,这是不正确的:
public static string EncryptText(string PlainText, string siteSecret)
{
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.PKCS7;
var bytes = Encoding.UTF8.GetBytes(siteSecret);
SHA1 sha1 = SHA1.Create();
var shaKey = sha1.ComputeHash(bytes);
byte[] targetArray = new byte[16];
Array.Copy(shaKey, targetArray, 16);
aes.Key = targetArray;
ICryptoTransform encrypto = aes.CreateEncryptor();
byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(PlainText);
byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
return HttpServerUtility.UrlTokenEncode(CipherText); //Equivalent to java's BaseEncoding.base64Url()?
}
}
C# 版本生成的值不正确:Ye+fySvneVUZJXth67+Si/e8fBUV4Sxs7wEXVDEOJjBMHl1encvt65gGIj8CiFzBGp5uUgKYJZCuQ4rc964vZigjlrJ/430LgYcathLLd9U=
【问题讨论】:
-
实现了 SHA1 哈希,仍然没有乐趣。
-
您可以尝试使用
AesManaged而不是RijndaelManaged(默认情况下具有不同的密钥大小,因此不是标准 AES)以匹配Java部分CIPHER_INSTANCE_NAME = "AES/ECB/PKCS5Padding"并使用Convert.ToBase64String而不是HttpServerUtility.UrlTokenEncode...。 -
更新为包含 c# 输出。 @pasty 我更新为
AESManaged,但不清楚我将如何与密码名称保持一致。我选择了PaddingMode.PKCS7每blog.zebsadiq.com/post/…,但我承认我一直在摸索。更改为Convert.ToBase64String对结果没有影响。我选择了HttpServerUtility.UrlTokenEncode,因为它似乎最接近 Java 的 BaseEncoding.base64Url()。 -
@pasty RijndaelManaged的块大小是128 bit by default,所以在功能上和AesManaged是等价的。
-
@ArtjomB。谢谢你的提示,我以为是 256。
标签: java c# encryption