Last active
August 17, 2017 19:48
-
-
Save dbeattie71/44ea3a13145f185d303e620c299ab1c5 to your computer and use it in GitHub Desktop.
Attempt to port Cognito authentication to C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Security.Cryptography; | |
using System.Text; | |
using Org.BouncyCastle.Crypto; | |
using Org.BouncyCastle.Crypto.Digests; | |
using Org.BouncyCastle.Math; | |
namespace ConsoleApp3 | |
{ | |
//https://gist.github.com/guywald/7a753e032ca2f979453b7f8aa4fb6569 | |
//https://gist.github.com/KonajuGames/0253adf035d83e3b58a872fb00e4f398 | |
public class AuthenticationHelper | |
{ | |
private const string InitN = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" | |
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" | |
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" | |
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" | |
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" | |
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" | |
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" | |
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" | |
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" | |
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" | |
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" | |
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" | |
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" | |
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" | |
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" | |
+ "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"; | |
public const string NewPasswordRequiredChallengeUserAttributePrefix = "userAttributes."; | |
private const string DerivedKeyInfo = "Caldera Derived Key"; | |
private const int DerivedKeySize = 16; | |
private readonly BigInteger _a; | |
public BigInteger A; | |
private readonly BigInteger _g; | |
private readonly BigInteger _k; | |
public BigInteger N; | |
private readonly string _userPoolId; | |
public AuthenticationHelper(string userPool) | |
{ | |
N = new BigInteger(InitN, 16); | |
_g = new BigInteger("2"); | |
_k = new BigInteger(1, Hash(N.ToByteArray(), _g.ToByteArray())); | |
var random = new Random(); | |
do | |
{ | |
_a = new BigInteger(1024, random).Mod(N); | |
A = _g.ModPow(_a, N); | |
} while (Equals(A.Mod(N), BigInteger.Zero)); | |
_userPoolId = userPool.Substring(userPool.IndexOf('_') + 1); | |
} | |
public byte[] GetPasswordAuthenticationKey(string userId, string userPassword, BigInteger b, BigInteger salt) | |
{ | |
var u = new BigInteger(1, Hash(A.ToByteArray(), b.ToByteArray())); | |
var usernamePassword = $"{_userPoolId}{userId}:{userPassword}"; | |
var userIdhash10 = HmacSha256Hash(usernamePassword); | |
var x = new BigInteger(1, Hash(salt.ToByteArray(), userIdhash10)); | |
var s = Mod(b.Subtract(_k.Multiply(_g.ModPow(x, N))).ModPow(_a.Add(u.Multiply(x)), N), N); | |
var hmac = new HMACSHA256(); | |
var hkdf = new HKDF(hmac, s.ToByteArray(), u.ToByteArray()); | |
return hkdf.Expand(Encoding.UTF8.GetBytes(DerivedKeyInfo), DerivedKeySize); | |
} | |
public static byte[] Hash(params byte[][] blocks) | |
{ | |
IDigest hash = new Sha256Digest(); | |
var result = new byte[hash.GetDigestSize()]; | |
foreach (var block in blocks) | |
hash.BlockUpdate(block, 0, block.Length); | |
hash.DoFinal(result, 0); | |
return result; | |
} | |
public static byte[] HmacSha256Hash(params string[] values) | |
{ | |
IDigest hash = new Sha256Digest(); | |
var result = new byte[hash.GetDigestSize()]; | |
foreach (var value in values) | |
{ | |
var bytes = Encoding.ASCII.GetBytes(value); | |
hash.BlockUpdate(bytes, 0, bytes.Length); | |
} | |
hash.DoFinal(result, 0); | |
return result; | |
} | |
private static BigInteger Mod(BigInteger dividend, BigInteger divisor) | |
{ | |
// Apparently needed for negative dividends, according to AWS SDK for iOS | |
return divisor.Add(dividend.Remainder(divisor)).Remainder(divisor); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* MIT LICENSE | |
Copyright (c) 2017 Markus Lachinger <[email protected]> | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
*/ | |
using Amazon.Runtime; | |
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using Amazon.CognitoIdentityProvider.Model; | |
using System.Security.Cryptography; | |
using Org.BouncyCastle.Security; | |
using Org.BouncyCastle.Math; | |
using System.Globalization; | |
namespace Com.Mmlac.Blog.IO | |
{ | |
class Authentication | |
{ | |
private static String AWS_CLIENT_ID = <insert your client ID here as String>; | |
public Authentication() { } | |
public static void LoginUser(String username, String password) | |
{ | |
var AWS_REGION = //TODO: change to the region your pool is in! i.e.: Amazon.RegionEndpoint.USWest2 | |
String POOL_NAME = <insert pool name here as String>; // (without the region identifier. It is usually <region>_<name>, just the name part here!) | |
AnonymousAWSCredentials cred = new AnonymousAWSCredentials(); | |
// Identify your Cognito UserPool Provider | |
using (var provider = new Amazon.CognitoIdentityProvider.AmazonCognitoIdentityProviderClient(cred, AWS_REGION)) | |
{ | |
//Get the SRP variables A and a | |
var TupleAa = AuthenticationHelper.CreateAaTuple(); | |
//Initiate auth with the generated SRP A | |
var authResponse = provider.InitiateAuth(new InitiateAuthRequest | |
{ | |
ClientId = AWS_CLIENT_ID, | |
AuthFlow = Amazon.CognitoIdentityProvider.AuthFlowType.USER_SRP_AUTH, | |
AuthParameters = new Dictionary<string, string>() { | |
{ "USERNAME", username }, | |
{ "SRP_A", TupleAa.Item1.ToString(16) } | |
} | |
}); | |
//Now with the authResponse containing the password challenge for us, we need to | |
//set up a reply | |
//ChallengeParameters SALT, SECRET_BLOCK, SRP_B, USERNAME, USER_ID_FOR_SRP | |
DateTime timestamp = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now); | |
//The timestamp format returned to AWS _needs_ to be in US Culture | |
CultureInfo usCulture = new CultureInfo("en-US"); | |
String timeStr = timestamp.ToString("ddd MMM d HH:mm:ss \"UTC\" yyyy", usCulture); | |
//Do the hard work to generate the claim we return to AWS | |
byte[] claim = AuthenticationHelper.authenticateUser(authResponse.ChallengeParameters["USERNAME"], | |
"password", | |
POOL_NAME, | |
TupleAa, | |
authResponse.ChallengeParameters["SALT"], | |
authResponse.ChallengeParameters["SRP_B"], | |
authResponse.ChallengeParameters["SECRET_BLOCK"], | |
timeStr | |
); | |
String claimBase64 = System.Convert.ToBase64String(claim); | |
//Our response to AWS. If successful it will return an object with Tokens, | |
//if unsuccessful, it will throw an Exception that you should catch and handle. | |
var resp = provider.RespondToAuthChallenge(new RespondToAuthChallengeRequest | |
{ | |
ChallengeName = authResponse.ChallengeName, | |
ClientId = "7dqval98fp7b0cmin849q97h7i", | |
ChallengeResponses = new Dictionary<string, string>() { | |
{ "PASSWORD_CLAIM_SECRET_BLOCK", authResponse.ChallengeParameters["SECRET_BLOCK"] }, | |
{ "PASSWORD_CLAIM_SIGNATURE", claimBase64 }, | |
{ "USERNAME", "mmlac" }, | |
{ "TIMESTAMP", timeStr } | |
} | |
}); | |
Console.WriteLine(""); //Statement for the debugger to hook | |
// From here on you either have your keys and the auth was successful, or you need to prompt your | |
// user for the correct credentials again. Or something else went wrong, the Exception contains the | |
// specific error text returned from AWS | |
} | |
} | |
} | |
/** | |
* Class for SRP client side math. | |
*/ | |
class AuthenticationHelper | |
{ | |
// static variables | |
private static String HEX_N = | |
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" | |
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" | |
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" | |
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" | |
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" | |
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" | |
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" | |
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" | |
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" | |
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" | |
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" | |
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" | |
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" | |
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" | |
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" | |
+ "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"; | |
public static BigInteger N = new BigInteger(HEX_N, 16); | |
private static BigInteger g = BigInteger.ValueOf(2); | |
public static BigInteger k; | |
public static int EPHEMERAL_KEY_LENGTH = 1024; | |
public static int DERIVED_KEY_SIZE = 16; | |
public static String DERIVED_KEY_INFO = "Caldera Derived Key"; | |
public static SecureRandom SECURE_RANDOM; | |
//static initializer | |
static AuthenticationHelper() | |
{ | |
SECURE_RANDOM = SecureRandom.GetInstance("SHA1PRNG"); | |
HashAlgorithm messageDigest = THREAD_MESSAGE_DIGEST; | |
byte[] nArr = N.ToByteArray(); | |
byte[] gArr = g.ToByteArray(); | |
byte[] content = new byte[nArr.Length + gArr.Length]; | |
Buffer.BlockCopy(nArr, 0, content, 0, nArr.Length); | |
Buffer.BlockCopy(gArr, 0, content, nArr.Length, gArr.Length); | |
byte[] digest = messageDigest.ComputeHash(content); | |
k = new BigInteger(1, digest); | |
Console.WriteLine(); | |
} | |
[ThreadStatic] private static HashAlgorithm THREAD_MESSAGE_DIGEST = HashAlgorithm.Create("SHA-256"); | |
// methods below - all stateless | |
// return the Tuple of ( A, a ) | |
public static Tuple<BigInteger, BigInteger> CreateAaTuple() | |
{ | |
BigInteger a, A; | |
do | |
{ | |
a = new BigInteger(EPHEMERAL_KEY_LENGTH, SECURE_RANDOM).Mod(N); | |
A = g.ModPow(a, N); | |
} while (A.Mod(N).Equals(BigInteger.Zero)); | |
return Tuple.Create<BigInteger, BigInteger>(A, a); | |
} | |
//raturns the claim | |
public static byte[] authenticateUser(String username, | |
String password, | |
String poolName, | |
Tuple<BigInteger, BigInteger> TupleAa, | |
String saltString, | |
String srp_b, | |
String secretBlock, | |
String formattedTimestamp) | |
{ | |
byte[] authSecretBlock = System.Convert.FromBase64String(secretBlock); | |
BigInteger B = new BigInteger(srp_b, 16); | |
if (B.Mod(AuthenticationHelper.N).Equals(BigInteger.Zero)) | |
{ | |
throw new Exception("B cannot be zero"); | |
} | |
BigInteger salt = new BigInteger(saltString, 16); | |
// We need to generate the key to hash the response based on our A and what AWS sent back | |
byte[] key = getPasswordAuthenticationKey(username, password, poolName, TupleAa, B, salt); | |
// HMAC our data with key (HKDF(S)) (the shared secret) | |
byte[] hmac; | |
try | |
{ | |
HMAC mac = HMAC.Create("HMACSHA256"); | |
mac.Key = key; | |
//bytes bytes bytes.... | |
byte[] poolNameByte = Encoding.UTF8.GetBytes(poolName); | |
byte[] name = Encoding.UTF8.GetBytes(username); | |
//secretBlock here | |
byte[] timeByte = Encoding.UTF8.GetBytes(formattedTimestamp); | |
byte[] content = new byte[poolNameByte.Length + name.Length + authSecretBlock.Length + timeByte.Length]; | |
Buffer.BlockCopy(poolNameByte, 0, content, 0, poolNameByte.Length); | |
Buffer.BlockCopy(name, 0, content, poolNameByte.Length, name.Length); | |
Buffer.BlockCopy(authSecretBlock, 0, content, poolNameByte.Length + name.Length, authSecretBlock.Length); | |
Buffer.BlockCopy(timeByte, 0, content, poolNameByte.Length + name.Length + authSecretBlock.Length, timeByte.Length); | |
hmac = mac.ComputeHash(content); | |
} | |
catch (Exception e) | |
{ | |
throw new Exception("Exception in authentication", e); | |
} | |
return hmac; | |
} | |
public static byte[] getPasswordAuthenticationKey(String userId, | |
String userPassword, | |
String poolName, | |
Tuple<BigInteger, BigInteger> Aa, | |
BigInteger B, | |
BigInteger salt) | |
{ | |
// Authenticate the password | |
// u = H(A, B) | |
HashAlgorithm messageDigest = THREAD_MESSAGE_DIGEST; | |
byte[] aArr = Aa.Item1.ToByteArray(); | |
byte[] bArr = B.ToByteArray(); | |
byte[] content = new byte[aArr.Length + bArr.Length]; | |
Buffer.BlockCopy(aArr, 0, content, 0, aArr.Length); | |
Buffer.BlockCopy(bArr, 0, content, aArr.Length, bArr.Length); | |
byte[] digest = messageDigest.ComputeHash(content); | |
BigInteger u = new BigInteger(1, digest); | |
if (u.Equals(BigInteger.Zero)) | |
{ | |
throw new Exception("Hash of A and B cannot be zero"); | |
} | |
// x = H(salt | H(poolName | userId | ":" | password)) | |
byte[] poolArr = Encoding.UTF8.GetBytes(poolName); | |
byte[] idArr = Encoding.UTF8.GetBytes(userId); | |
byte[] colonArr = Encoding.UTF8.GetBytes(":"); | |
byte[] passArr = Encoding.UTF8.GetBytes(userPassword); | |
byte[] userIdContent = new byte[poolArr.Length + idArr.Length + colonArr.Length + passArr.Length]; | |
Buffer.BlockCopy(poolArr, 0, userIdContent, 0, poolArr.Length); | |
Buffer.BlockCopy(idArr, 0, userIdContent, poolArr.Length, idArr.Length); | |
Buffer.BlockCopy(colonArr, 0, userIdContent, poolArr.Length + idArr.Length, colonArr.Length); | |
Buffer.BlockCopy(passArr, 0, userIdContent, poolArr.Length + idArr.Length + colonArr.Length, passArr.Length); | |
byte[] userIdHash = messageDigest.ComputeHash(userIdContent); | |
byte[] saltArr = salt.ToByteArray(); | |
byte[] xArr = new byte[saltArr.Length + userIdHash.Length]; | |
Buffer.BlockCopy(saltArr, 0, xArr, 0, saltArr.Length); | |
Buffer.BlockCopy(userIdHash, 0, xArr, saltArr.Length, userIdHash.Length); | |
byte[] xDigest = messageDigest.ComputeHash(xArr); | |
BigInteger x = new BigInteger(1, xDigest); | |
BigInteger S = (B.Subtract(k.Multiply(g.ModPow(x, N))).ModPow(Aa.Item2.Add(u.Multiply(x)), N)).Mod(N); | |
Hkdf hkdf = new Hkdf(); | |
byte[] key = hkdf.DeriveKey(u.ToByteArray(), S.ToByteArray(), Encoding.UTF8.GetBytes(DERIVED_KEY_INFO), DERIVED_KEY_SIZE); | |
return key; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//https://gist.github.com/charlesportwoodii/7c5cf32e92ee88fec5e8f3270d0b44fc | |
using System; | |
using System.IO; | |
using System.Security.Cryptography; | |
namespace ConsoleApp3 | |
{ | |
/// <summary> | |
/// HMAC-based Extract-and-Expand Key Derivation Function (HKDF) | |
/// https://tools.ietf.org/html/rfc5869 | |
/// </summary> | |
public class HKDF | |
{ | |
private readonly int hashLength; | |
private readonly HMAC hmac; | |
private readonly byte[] prk; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="HKDF" /> class. | |
/// </summary> | |
/// <param name="hmac">The HMAC hash function to use.</param> | |
/// <param name="ikm">input keying material.</param> | |
/// <param name="salt"> | |
/// optional salt value (a non-secret random value); if not provided, it is set to a string of | |
/// HMAC.HashSize/8 zeros. | |
/// </param> | |
public HKDF(HMAC hmac, byte[] ikm, byte[] salt = null) | |
{ | |
this.hmac = hmac; | |
hashLength = hmac.HashSize / 8; | |
// now we compute the PRK | |
hmac.Key = salt ?? new byte[hashLength]; | |
prk = hmac.ComputeHash(ikm); | |
} | |
/// <summary> | |
/// Expands the specified info. | |
/// </summary> | |
/// <param name="info">optional context and application specific information (can be a zero-length string)</param> | |
/// <param name="l">length of output keying material in octets (<= 255*HashLen)</param> | |
/// <returns>OKM (output keying material) of L octets</returns> | |
public byte[] Expand(byte[] info, int l) | |
{ | |
if (info == null) info = new byte[0]; | |
hmac.Key = prk; | |
var n = (int) Math.Ceiling(l * 1f / hashLength); | |
var t = new byte[n * hashLength]; | |
using (var ms = new MemoryStream()) | |
{ | |
var prev = new byte[0]; | |
for (var i = 1; i <= n; i++) | |
{ | |
ms.Write(prev, 0, prev.Length); | |
if (info.Length > 0) ms.Write(info, 0, info.Length); | |
ms.WriteByte((byte) (0x01 * i)); | |
prev = hmac.ComputeHash(ms.ToArray()); | |
Array.Copy(prev, 0, t, (i - 1) * hashLength, hashLength); | |
ms.SetLength(0); //reset | |
} | |
} | |
var okm = new byte[l]; | |
Array.Copy(t, okm, okm.Length); | |
return okm; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Globalization; | |
using System.Net; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Amazon; | |
using Amazon.CognitoIdentityProvider; | |
using Amazon.CognitoIdentityProvider.Model; | |
using Amazon.Runtime; | |
using Amazon.Runtime.Internal; | |
using Amazon.Runtime.Internal.Util; | |
using Amazon.Util; | |
using Org.BouncyCastle.Crypto.Parameters; | |
using Org.BouncyCastle.Math; | |
using Org.BouncyCastle.Security; | |
namespace ConsoleApp3 | |
{ | |
//https://gist.github.com/KonajuGames/0253adf035d83e3b58a872fb00e4f398 | |
//http://stackoverflow.com/questions/12185122/calculating-hmacsha256-using-c-sharp-to-match-payment-provider-example | |
//http://pastebin.com/xAAuZrJX | |
public class Program | |
{ | |
private const string ClientId = ""; | |
private const string ClientSecret = ""; | |
private const string UserPoolId = ""; | |
private const string Email = ""; | |
public static void Main(string[] args) | |
{ | |
var p = new Program(); | |
p.Test1(); | |
Console.WriteLine("done..."); | |
Console.ReadLine(); | |
} | |
public string SecretHash() | |
{ | |
return CryptoUtilFactory.CryptoInstance.HMACSign($"{Email}{ClientId}", ClientSecret, | |
SigningAlgorithm.HmacSHA256); | |
} | |
public async Task Test1() | |
{ | |
try | |
{ | |
//AWSConfigs.ProxyConfig.Host = "127.0.0.1"; | |
//AWSConfigs.ProxyConfig.Port = 8888; | |
WebRequest.DefaultWebProxy = new WebProxy("127.0.0.1", 8888); | |
var authenticationHelper = new AuthenticationHelper(UserPoolId); | |
var authParams = new AutoConstructedDictionary<string, string> | |
{ | |
["SECRET_HASH"] = SecretHash(), | |
["USERNAME"] = Email, | |
["SRP_A"] = authenticationHelper.A.ToString(16), | |
["DEVICE_KEY"] = null | |
}; | |
var request = new InitiateAuthRequest | |
{ | |
AuthFlow = AuthFlowType.USER_SRP_AUTH, | |
AuthParameters = authParams, | |
ClientId = ClientId | |
}; | |
var amazonCognitoIdentityProviderClient = new AmazonCognitoIdentityProviderClient(RegionEndpoint.USEast1); | |
var response = await amazonCognitoIdentityProviderClient.InitiateAuthAsync(request); | |
var userIdForSrp = response.ChallengeParameters["USER_ID_FOR_SRP"]; | |
var userIdForSrpBytes = Encoding.UTF8.GetBytes(userIdForSrp); | |
var b = new BigInteger(response.ChallengeParameters["SRP_B"], 16); | |
if (Equals(b.Mod(authenticationHelper.N), BigInteger.Zero)) | |
throw new InvalidOperationException("SRP error, B cannot be zero"); | |
var salt = new BigInteger(response.ChallengeParameters["SALT"], 16); | |
var key = authenticationHelper.GetPasswordAuthenticationKey(userIdForSrp, "MyPassword", b, salt); | |
var userPoolId = UserPoolId.Substring(UserPoolId.IndexOf('_') + 1); | |
var userPoolIdBytes = Encoding.UTF8.GetBytes(userPoolId); | |
var formatTimestamp = AWSSDKUtils.CorrectedUtcNow.ToString("ddd MMM d HH:mm:ss UTC yyyy", | |
CultureInfo.InvariantCulture); | |
var keySpec = new KeyParameter(key); | |
var mac = MacUtilities.GetMac("HMAC-SHA_256"); | |
mac.Init(keySpec); | |
mac.BlockUpdate(userPoolIdBytes, 0, userPoolId.Length); | |
mac.BlockUpdate(userIdForSrpBytes, 0, userIdForSrpBytes.Length); | |
var secretBlock = Convert.FromBase64String(response.ChallengeParameters["SECRET_BLOCK"]); | |
mac.BlockUpdate(secretBlock, 0, secretBlock.Length); | |
var dateString = AWSSDKUtils.CorrectedUtcNow.ToString("ddd MMM d HH:mm:ss UTC yyyy", | |
CultureInfo.InvariantCulture); | |
var dateBytes = Encoding.UTF8.GetBytes(dateString); | |
mac.BlockUpdate(dateBytes, 0, dateBytes.Length); | |
var hmac = new byte[mac.GetMacSize()]; | |
mac.DoFinal(hmac, 0); | |
var claimSignature = Convert.ToBase64String(hmac); | |
var srpAuthResponses = new AutoConstructedDictionary<string, string> | |
{ | |
["PASSWORD_CLAIM_SECRET_BLOCK"] = response.ChallengeParameters["SECRET_BLOCK"], | |
["PASSWORD_CLAIM_SIGNATURE"] = claimSignature, | |
["TIMESTAMP"] = formatTimestamp, | |
["USERNAME"] = response.ChallengeParameters["USERNAME"], | |
["DEVICE_KEY"] = null, | |
["SECRET_HASH"] = SecretHash() | |
}; | |
var authChallengeRequest = new RespondToAuthChallengeRequest | |
{ | |
ChallengeName = response.ChallengeName, | |
ChallengeResponses = srpAuthResponses, | |
ClientId = ClientId, | |
Session = response.Session | |
}; | |
var authChallengeResponse = | |
await amazonCognitoIdentityProviderClient.RespondToAuthChallengeAsync(authChallengeRequest); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine(e); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm getting username or password is incorrect. Where would you even start debugging this