2015-11-03 75 views
2

我試圖在nodejs中實現reCaptcha Secure Tokens在與.net不同的節點中創建的安全令牌

看着在Java.NET的例子進行,創造了這個版本的節點:

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中,我得到一個可行的令牌(使用不包含在後右鍵),但在節點我得到了相同的輸入不同的令牌,它不工作:

.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

回答

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 
+0

大!upvoted和接受,我懷疑這個自訂JSON產生了一點,但沒有正確調試它抓住不同的位,使用錯誤的方法創建密碼是一個初學者的錯誤(好吧,我是一個節點加密中的begginer),現在我會站在角落裏,謝謝 –