2017-02-09 1 views
0

Microsoft의 ID 모델 토큰을 사용하여 여러 웹 사이트에서 로그인 한 사용자를 인증하려고합니다. HmacSha256 알고리즘을 사용하여이 작업을 수행했지만 회사에서 AES256을 사용해야합니다. 아픈 쇼 코드,하지만 내 질문에 누군가가 AES256 서명 알고리즘을 사용하여 토큰을 만드는 방법을 알고 있습니까? 은 무엇 작동합니다AES256 서명 자격 증명으로 jwt 사용

var plainTextSecurityKey = "My very large security key to encrypt and pass in a token"; 


var signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.Default.GetBytes(plainTextSecurityKey)); 
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(signingKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256); 

var header = new JwtHeader(signingCredentials); 

var claimsIdentity = new ClaimsIdentity(new List<Claim>() 
{ 
    new Claim(ClaimTypes.Name,<passedinlanid>), 
    new Claim(ClaimTypes.Role,<passedinrole>), 
}, "Custom"); 

var securityTokenDescriptor = new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor() 
{ 
    Audience = "https://myurl.com", 
    Issuer = "http://my.tokenissuer.com", 
    Subject = claimsIdentity, 
    SigningCredentials = signingCredentials, 
}; 

var tokenHandler = new JwtSecurityTokenHandler(); 
var plainToken = tokenHandler.CreateToken(securityTokenDescriptor); 
var signedAndEncodedToken = tokenHandler.WriteToken(plainToken); 

은 내가 사용해야하는 줄

var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(signingKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.Aes256Encryption); 

하지만 난이 오류 ({ "IDX10634 :. SignatureProvider을 만들 수 없습니다 \ nAlgorithm : 'http://www.w3.org/2001/04/xmlenc#aes256-cbc', SecurityKey : 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey'\ n은 지원되지 않습니다. "}) var plainToken = tokenHandler.CreateToken (securityTokenDescriptor);

이제 오류의 의미를 이해합니다. JWT를 사용하여 AES256 암호화를 사용할 방법이 있는지 모르겠습니까?

+0

이 오류는 사용중인 라이브러리 및 플랫폼에서 지원되지 않는 알고리즘을 요청한 것 같습니다. 어떤 플랫폼과 라이브러리를 사용하고 있는지 자세히 설명해 주시겠습니까? – yfisaqt

+0

.NET 4.5.2, C# 및 모두를 사용하고 있습니다 System.IdentityModel.Tokens.Jwt; Microsoft.IdentityModel.Tokens; – Scott

+0

답변이 필요할 수있는 사람에게 해결책을 찾은 것 같습니다. 내가 한 일은 HmacSha256 알고리즘을 통해 토큰을 만든 다음 AES256 알고리즘으로 그 토큰을 암호화 한 것입니다. 그런 다음 httpOnly 쿠키에 저장됩니다. 수신 측에서는 쿠키 값을 읽고 AES256 문자열을 해독 한 다음 정상적으로 토큰을 확인합니다. 이 암호화 과잉 될 수 있습니다 이해하지만 내 회사는 AES256 사용해야합니다. 대답에 내 코드를 게시하십시오. – Scott

답변

0

이것은 최종 코드입니다.

public string GetJwtToken(String lanID,string Role) 
     { 


      var plainText = lanID + "-" + ConfigurationManager.AppSettings["TokenText"].ToString(); 
      var plainTextSecurityKey = lanID + "-" + ConfigurationManager.AppSettings["TokenKey"].ToString(); 
      var signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.Default.GetBytes(plainText)); 
      var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(signingKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256); 

      var header = new JwtHeader(signingCredentials); 

      var claimsIdentity = new ClaimsIdentity(new List<Claim>() 
      { 
       new Claim(ClaimTypes.Name, lanID), 
       new Claim(ClaimTypes.Role,Role), 
      }, "Custom"); 

      var securityTokenDescriptor = new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor() 
      { 
       Audience = "https://myvalidaud.com", 
       Issuer = "http://my.tokenissuer.com", 
       Subject = claimsIdentity, 
       SigningCredentials = signingCredentials, 
      }; 

      var tokenHandler = new JwtSecurityTokenHandler(); 
      var plainToken = tokenHandler.CreateToken(securityTokenDescriptor); 

      //we encrypt the token with AES256 
      var signedAndEncodedToken = Encrypt(tokenHandler.WriteToken(plainToken), plainTextSecurityKey); 

      //after this is returned its assigned to a cookie 
      return signedAndEncodedToken; 
     } 



     public static Boolean ValidateJwt(string jwt,string lanId) 
     { 

      var handler = new JwtSecurityTokenHandler(); 
      var plainText = lanId + "-" + ConfigurationManager.AppSettings["TokenText"].ToString(); 
      var plainTextSecurityKey = lanId + "-" + ConfigurationManager.AppSettings["TokenKey"].ToString(); 

      //decrypt jwt from AES first 
      jwt = Decrypt(jwt, plainTextSecurityKey); 

      var signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.Default.GetBytes(plainText)); 

      var validationParameters = new TokenValidationParameters() 
      { 
       ValidAudiences = new string[] 
       { 
        "https://myvalidaud.com" 

       }, 
       ValidIssuers = new string[] 
       { 
        "http://my.tokenissuer.com", 
        "http://my.othertokenissuer.com" 
       }, 
       IssuerSigningKey = signingKey 
      }; 

      try 
      { 
       Microsoft.IdentityModel.Tokens.SecurityToken validatedToken; 
       handler.ValidateToken(jwt, validationParameters, out validatedToken); 
       return true; 
      } 
      catch (Exception e) 
      { 
       return false; 

      } 


     } 

     //AES has fixed BLOCK size of 128 bits, and a variable KEY size of 128, 192, or 256 bits. The key size is what discerns AES-128 from AES-256, block size is always 128 
     //Salt size of 32 bytes makes a 256 bits 
     public static string Encrypt(string plainText, string key) 
     { 
      if (string.IsNullOrEmpty(plainText)) 
       throw new ArgumentNullException("plainText"); 
      if (string.IsNullOrEmpty(key)) 
       throw new ArgumentNullException("key"); 

      // Derive a new Salt and IV from the Key 
      using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, _saltSize)) 
      { 
       var saltBytes = keyDerivationFunction.Salt; 
       var keyBytes = keyDerivationFunction.GetBytes(32); 
       var ivBytes = keyDerivationFunction.GetBytes(16); 

       // Create an encryptor to perform the stream transform. 
       // Create the streams used for encryption. 
       using (var aesManaged = new AesManaged()) 
       using (var encryptor = aesManaged.CreateEncryptor(keyBytes, ivBytes)) 
       using (var memoryStream = new MemoryStream()) 
       { 
        using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) 
        using (var streamWriter = new StreamWriter(cryptoStream)) 
        { 
         // Send the data through the StreamWriter, through the CryptoStream, to the underlying MemoryStream 
         streamWriter.Write(plainText); 
        } 

        // Return the encrypted bytes from the memory stream, in Base64 form so we can send it right to a database (if we want). 
        var cipherTextBytes = memoryStream.ToArray(); 
        Array.Resize(ref saltBytes, saltBytes.Length + cipherTextBytes.Length); 
        Array.Copy(cipherTextBytes, 0, saltBytes, _saltSize, cipherTextBytes.Length); 

        return Convert.ToBase64String(saltBytes); 
       } 
      } 
     } 


     public static string Decrypt(string ciphertext, string key) 
     { 
      if (string.IsNullOrEmpty(ciphertext)) 
       throw new ArgumentNullException("cipherText"); 
      if (string.IsNullOrEmpty(key)) 
       throw new ArgumentNullException("key"); 

      // Extract the salt from our ciphertext 
      var allTheBytes = Convert.FromBase64String(ciphertext); 
      var saltBytes = allTheBytes.Take(_saltSize).ToArray(); 
      var ciphertextBytes = allTheBytes.Skip(_saltSize).Take(allTheBytes.Length - _saltSize).ToArray(); 

      using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, saltBytes)) 
      { 
       // Derive the previous IV from the Key and Salt 
       var keyBytes = keyDerivationFunction.GetBytes(32); 
       var ivBytes = keyDerivationFunction.GetBytes(16); 

       // Create a decrytor to perform the stream transform. 
       // Create the streams used for decryption. 
       // The default Cipher Mode is CBC and the Padding is PKCS7 which are both good 
       using (var aesManaged = new AesManaged()) 
       using (var decryptor = aesManaged.CreateDecryptor(keyBytes, ivBytes)) 
       using (var memoryStream = new MemoryStream(ciphertextBytes)) 
       using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) 
       using (var streamReader = new StreamReader(cryptoStream)) 
       { 
        // Return the decrypted bytes from the decrypting stream. 
        return streamReader.ReadToEnd(); 
       } 
      } 
     } 
관련 문제