我试图在nodejs中实现reCaptcha Secure Tokens。
exports.getSecureToken = function() {
var algorithm = 'aes-128-ecb';
var tokenObj = { session_id: 'ab0069ec-3c2c-436c-868b-43c7a10db229'/*uuid.v4()*/, ts_ms: 1446560931992/*(new Date()).getTime()*/ };
var text = JSON.stringify(tokenObj);
var shaHash = new Buffer(crypto.createHash('sha1').update('6LeyNOTTVALIDH2RLNaivqrrpm2zh56Y3uHqOjFO'/*config.reCAPTCHASecret*/).digest('hex'), 'hex');
var key = shaHash.slice(0, 16);
var cipher = crypto.createCipher(algorithm, key, key);
var encryptedToken = cipher.update(text, 'utf8', 'base64') + cipher.final('base64');
var result = encryptedToken.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
return result;
};
问题是在.NET中我获得了一个有效的令牌(使用了帖子中没有包含的右键),但是在节点中我得到了相同输入的不同令牌,但它不起作用:< / p>
.NET - LhPTUELia5vc0X6aDGDtqpsbmB7oqm6vUnzk5BL2auactYXRU5TEUzML8gZ_JubXG07rvJxk1Sb5_a-wqVUGEf_UuO1gGi-WO83yJHOxnjI
节点 - EGr7drd1JEylwzLGakZ6dpPRSf2nFdpzHOrJlLZlyHYmVRj5obAw7WjPt4W5l0vsywNEqCQ-2_d7qIZOMiOedianfBrQPOBaOmmq44IOB8Q
我在加密之前看到密钥和输入是相同的(在.NET和节点中),所以问题必须(?)是密码,任何线索?
.NET代码供参考:
public static void Main(string[] args)
{
//Your code goes here
Console.WriteLine(EncryptJsonToken(GetJsonToken()));
}
public static string GetJsonToken()
{
//Example: {"session_id": e6e9c56e-a7da-43b8-89fa-8e668cc0b86f,"ts_ms":1421774317718}
string jsonRequest = "{" + string.Format("\"session_id\": {0},\"ts_ms\":{1}", "ab0069ec-3c2c-436c-868b-43c7a10db229", 1446560931992) + "}";
return jsonRequest;
}
public static byte[] getKey()
{
string secretKey = "6LeyNOTTVALIDH2RLNaivqrrpm2zh56Y3uHqOjFO";
SHA1 sha = SHA1.Create();
byte[] dataToHash = Encoding.UTF8.GetBytes(secretKey);
byte[] shaHash = sha.ComputeHash(dataToHash);
byte[] first16OfHash = new byte[16];
Array.Copy(shaHash, first16OfHash, 16);
return first16OfHash;
}
public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Mode = CipherMode.ECB;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
public static string EncryptJsonToken(string jsonToken)
{
byte[] encrypted = EncryptStringToBytes_Aes(jsonToken, getKey(), getKey());
//Base64 encode the encrypted data
//Also applys the URL variant of base64 encoding, unfortunately the HttpServerUtility.UrlTokenEncode(encrypted) seems to truncate the last value from the string so we can't use it?
return Convert.ToBase64String(encrypted, Base64FormattingOptions.None).Replace("=", String.Empty).Replace('+', '-').Replace('/', '_');
}
在.NET中进行调试:DEMO
答案 0 :(得分:3)
你有两个问题:
您正在使用JSON.stringify()
生成有效的JSON字符串,但C#代码中的GetJsonToken()
方法不会生成有效的JSON字符串。 UUID缺少"
,由于某种原因,session_id
键与其值之间存在空格。您必须在JavaScript中反映这些差异:
var uuidToken = "ab0069ec-3c2c-436c-868b-43c7a10db229";
var time = 1446560931992;
var text = "{\"session_id\": "+uuidToken+",\"ts_ms\":"+time+"}";
没有这样的功能crypto.createCipher(algorithm, key, key)
。但是crypto.createCipheriv(algorithm, key, iv)
。如果有密码而不是您没有的密钥,则可以使用createCipher(algorithm, password)
。由于ECB模式没有IV,您可以传入一个空的(二进制)字符串作为IV。
完整代码:
var crypto = require("crypto");
var algorithm = 'aes-128-ecb';
var uuidToken = "ab0069ec-3c2c-436c-868b-43c7a10db229";
var time = 1446560931992;
var text = "{\"session_id\": "+uuidToken+",\"ts_ms\":"+time+"}";
console.log("Token: " + text);
var shaHash = crypto.createHash('sha1').update('6LeyNOTTVALIDH2RLNaivqrrpm2zh56Y3uHqOjFO').digest();
var key = shaHash.slice(0, 16);
var cipher = crypto.createCipheriv(algorithm, key, "");
var encryptedToken = cipher.update(text, 'utf8', 'base64') + cipher.final('base64');
var result = encryptedToken.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
console.log("result: " + result);
console.log("expected: LhPTUELia5vc0X6aDGDtqpsbmB7oqm6vUnzk5BL2auactYXRU5TEUzML8gZ_JubXG07rvJxk1Sb5_a-wqVUGEf_UuO1gGi-WO83yJHOxnjI");
输出:
Token: {"session_id": ab0069ec-3c2c-436c-868b-43c7a10db229,"ts_ms":1446560931992} result: LhPTUELia5vc0X6aDGDtqpsbmB7oqm6vUnzk5BL2auactYXRU5TEUzML8gZ_JubXG07rvJxk1Sb5_a-wqVUGEf_UuO1gGi-WO83yJHOxnjI expected: LhPTUELia5vc0X6aDGDtqpsbmB7oqm6vUnzk5BL2auactYXRU5TEUzML8gZ_JubXG07rvJxk1Sb5_a-wqVUGEf_UuO1gGi-WO83yJHOxnjI