/*
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
namespace Amazon.Extensions.CognitoAuthentication.Util
{
///
/// Class that helps with device SRP authentication
///
internal static class CognitoDeviceHelper
{
public static byte[] Salt { get; set; }
public static BigInteger Verifier { get; set; }
///
/// Generates the salt, verifier, and secret verification parameters for device SRP
///
/// The device key for the associated CognitoDevice
/// The device group key for the associated CognitoDevice
/// Returns a dictionary with key-value pairings for the salt, verifier, and secret for
/// the associated CognitoDevice
public static IDictionary GenerateVerificationParameters(string deviceKey, string deviceGroup)
{
string deviceSecret = GenerateRandomString();
GenerateDeviceSaltAndVerifier(deviceGroup, deviceKey, deviceSecret);
byte[] srpVerifier = Verifier.ToByteArray();
Dictionary verificationParams = new Dictionary()
{
{ "salt", Convert.ToBase64String(Salt) },
{ "verifier", Convert.ToBase64String(srpVerifier) },
{ "secret", deviceSecret }
};
return verificationParams;
}
///
/// Generates the device salt and verifier values and stores them in the appropriate
/// CognitoDeviceHelper properties
///
/// The device group key for the associated CognitoDevice
/// The device key for the CognitoDevice
/// The password for the CognitoUser associated with the device
public static void GenerateDeviceSaltAndVerifier(string deviceGroupKey, string deviceKey, string password)
{
byte[] deviceKeyHash = GetDeviceKeyHash(deviceGroupKey, deviceKey, password);
Salt = new byte[16];
using (var cryptoRandom = RandomNumberGenerator.Create())
{
cryptoRandom.GetBytes(Salt);
}
Verifier = CalculateVerifier(Salt, deviceKeyHash);
}
///
/// Calculates the device verifier for the device given the salt and device key hash
///
/// The salt for the SHA256 hash to compute the device verifier
/// The device key hash for the associated CognitoDevice
/// Returns the device verifier for the associated CognitoDevice
public static BigInteger CalculateVerifier(byte[] salt, byte[] deviceKeyHash)
{
byte[] contentBytes = CognitoAuthHelper.CombineBytes(salt, deviceKeyHash);
byte[] digest = CognitoAuthHelper.Sha256.ComputeHash(contentBytes);
BigInteger x = new BigInteger(digest);
return BigInteger.ModPow(x, AuthenticationHelper.g, AuthenticationHelper.N);
}
///
/// Computes the device key hash given the device group key, device key, and user password
///
/// The device group key for the CognitoDevice
/// The device key for the CognitoDevice
/// The password for the CognitoUser associated with the device
/// Returns the device key hash for the given device
public static byte[] GetDeviceKeyHash(string deviceGroupKey, string deviceKey, string password)
{
byte[] contentBytes = CognitoAuthHelper.CombineBytes(Encoding.UTF8.GetBytes(deviceGroupKey),
Encoding.UTF8.GetBytes(deviceKey), Encoding.UTF8.GetBytes(":"), Encoding.UTF8.GetBytes(password));
return CognitoAuthHelper.Sha256.ComputeHash(contentBytes);
}
///
/// Generates a random string using a globally unique identifier
///
/// Returns a random string
public static string GenerateRandomString()
{
return Guid.NewGuid().ToString();
}
}
}