internal static byte[] SignChallenge(OtpInfo otp, byte[] challenge, uint unixSeconds) { if (challenge.Length != ChallengeSize) { throw new ArgumentOutOfRangeException( "challenge", challenge.Length, string.Format("Challenge must be {0} bytes long", ChallengeSize)); } using (var s = new MemoryStream(1024)) { s.Write(otp.Suite, 0, otp.Suite.Length); s.WriteByte(0); s.Write(challenge, 0, challenge.Length); var z = BitConverter.GetBytes((UInt32)0); s.Write(z, 0, z.Length); var time = (unixSeconds - otp.StartTime) / otp.TimeStep; var t = BitConverter.GetBytes((UInt32)time); if (BitConverter.IsLittleEndian) { Array.Reverse(t); } s.Write(t, 0, t.Length); return(Hmac(otp.HmacSeed, s.ToArray())); } }
// Checks that the OTP info is something we can work with. The Chrome // extension also supports only this subset. They don't validate as much, // just assume the values are what they expect. public static void ValidateOtpInfo(OtpInfo otp) { Action <object, object, string> throwError = (actual, expected, name) => { throw new ArgumentException( string.Format("Invalid OTP {0} (expected {1}, got {2})", name, expected, actual)); }; Action <int, int, string> verify = (actual, expected, name) => { if (actual != expected) { throwError(actual, expected, name); } }; verify(otp.Version, 3, "version"); verify(otp.OtpAlgorithm, 1, "algorithm"); verify(otp.OtpLength, 0, "length"); verify(otp.HashAlgorithm, 2, "hash"); verify(otp.HmacSeed.Length, 32, "HMAC length"); verify(otp.Iptmk.Length, 32, "IPTMK length"); const string suite = "OCRA-1:HOTP-SHA256-0:QA08"; if (!otp.Suite.SequenceEqual(suite.ToBytes())) { throwError(otp.Suite, suite, "suite"); } }
internal static byte[] SignChallenge(OtpInfo otp, byte[] challenge, uint unixSeconds) { if (challenge.Length != ChallengeSize) { throw new InternalErrorException($"Challenge must be {ChallengeSize} bytes long"); } using var s = new MemoryStream(1024); s.Write(otp.Suite, 0, otp.Suite.Length); s.WriteByte(0); s.Write(challenge, 0, challenge.Length); var z = BitConverter.GetBytes(0u); s.Write(z, 0, z.Length); var time = (unixSeconds - otp.StartTime) / otp.TimeStep; var t = BitConverter.GetBytes((uint)time); if (BitConverter.IsLittleEndian) { Array.Reverse(t); } s.Write(t, 0, t.Length); return(Crypto.HmacSha256(otp.HmacSeed, s.ToArray())); }
public static OtpChallenge GenerateRandomOtpChallenge(OtpInfo otp) { var challenge = RandomBytes(ChallengeSize); var time = DateTime.UtcNow; return(new OtpChallenge(challenge, time, SignChallenge(otp, challenge, time.UnixSeconds()))); }
/// <summary> /// When overridden in a descendant class, deserializes the object from an XML according to Aadhaar API specification. /// </summary> /// <param name="element">An instance of <see cref="XElement"/>.</param> protected override void DeserializeXml(XElement element) { base.DeserializeXml(element); IsOtpSent = element.Attribute("ret").Value[0] == AadhaarHelper.Yes; var info = element.Attribute("info")?.Value; Info = info != null ? new OtpInfo { InfoValue = info } : null; }