summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Enzmann <christoph.enzmann@confer.ch>2013-12-06 16:50:33 +0100
committerChristoph Enzmann <christoph.enzmann@confer.ch>2013-12-06 16:50:33 +0100
commitea753e7a60e90f94bb9c89d91366e7968e4f4ce8 (patch)
tree653c5eebb2258134ecc95695fe742695eadd0582
parent41cb13ee263104981850a73d4abf4a583df31941 (diff)
downloadTwoStepsAuthenticator-ea753e7a60e90f94bb9c89d91366e7968e4f4ce8.zip
TwoStepsAuthenticator-ea753e7a60e90f94bb9c89d91366e7968e4f4ce8.tar.gz
TwoStepsAuthenticator-ea753e7a60e90f94bb9c89d91366e7968e4f4ce8.tar.bz2
Removed UsedCodesManager from CounterAuthenticator
-rw-r--r--TwoStepsAuthenticator.UnitTests/CounterAuthenticatorTests.cs23
-rw-r--r--TwoStepsAuthenticator.UnitTests/TimeAuthenticatorTests.cs13
-rw-r--r--TwoStepsAuthenticator.UnitTests/UsedCodesManagerTests.cs12
-rw-r--r--TwoStepsAuthenticator/Authenticator.cs1
-rw-r--r--TwoStepsAuthenticator/CounterAuthenticator.cs8
-rw-r--r--TwoStepsAuthenticator/IUsedCodesManager.cs4
-rw-r--r--TwoStepsAuthenticator/TimeAuthenticator.cs6
-rw-r--r--TwoStepsAuthenticator/UsedCodesManager.cs20
8 files changed, 40 insertions, 47 deletions
diff --git a/TwoStepsAuthenticator.UnitTests/CounterAuthenticatorTests.cs b/TwoStepsAuthenticator.UnitTests/CounterAuthenticatorTests.cs
index 3a81a90..f834178 100644
--- a/TwoStepsAuthenticator.UnitTests/CounterAuthenticatorTests.cs
+++ b/TwoStepsAuthenticator.UnitTests/CounterAuthenticatorTests.cs
@@ -9,27 +9,10 @@ namespace TwoStepsAuthenticator.UnitTests {
[TestFixture]
public class CounterAuthenticatorTests {
- private MockUsedCodesManager mockUsedCodesManager { get; set; }
-
- [SetUp]
- public void SetUp() {
- this.mockUsedCodesManager = new MockUsedCodesManager();
- }
-
- [Test]
- public void Uses_usedCodesManager() {
- var authenticator = new CounterAuthenticator(usedCodeManager: mockUsedCodesManager);
- var secret = Authenticator.GenerateKey();
- var code = authenticator.GetCode(secret, 42uL);
-
- authenticator.CheckCode(secret, code, 42uL);
- Assert.AreEqual(mockUsedCodesManager.LastChallenge, 42uL);
- Assert.AreEqual(mockUsedCodesManager.LastCode, code);
- }
[Test]
public void CreateKey() {
- var authenticator = new CounterAuthenticator(usedCodeManager: mockUsedCodesManager);
+ var authenticator = new CounterAuthenticator();
var secret = Authenticator.GenerateKey();
var code = authenticator.GetCode(secret, 0uL);
@@ -48,7 +31,7 @@ namespace TwoStepsAuthenticator.UnitTests {
[TestCase("12345678901234567890", 8uL, "399871")]
[TestCase("12345678901234567890", 9uL, "520489")]
public void VerifyKeys(string secret, ulong counter, string code) {
- var authenticator = new CounterAuthenticator(usedCodeManager: mockUsedCodesManager);
+ var authenticator = new CounterAuthenticator();
var base32Secret = Base32Encoding.ToString(Encoding.ASCII.GetBytes(secret));
Assert.IsTrue(authenticator.CheckCode(base32Secret, code, counter));
@@ -57,7 +40,7 @@ namespace TwoStepsAuthenticator.UnitTests {
[Test]
public void VerifyUsedCounter() {
- var authenticator = new CounterAuthenticator(usedCodeManager: mockUsedCodesManager);
+ var authenticator = new CounterAuthenticator();
// Test Values from http://www.ietf.org/rfc/rfc4226.txt - Appendix D
var base32Secret = Base32Encoding.ToString(Encoding.ASCII.GetBytes("12345678901234567890"));
diff --git a/TwoStepsAuthenticator.UnitTests/TimeAuthenticatorTests.cs b/TwoStepsAuthenticator.UnitTests/TimeAuthenticatorTests.cs
index 1a1ffc6..bc2f364 100644
--- a/TwoStepsAuthenticator.UnitTests/TimeAuthenticatorTests.cs
+++ b/TwoStepsAuthenticator.UnitTests/TimeAuthenticatorTests.cs
@@ -32,10 +32,23 @@ namespace TwoStepsAuthenticator.UnitTests {
var code = authenticator.GetCode(secret);
authenticator.CheckCode(secret, code);
+
Assert.AreEqual(mockUsedCodesManager.LastChallenge, 0uL);
Assert.AreEqual(mockUsedCodesManager.LastCode, code);
}
+ [Test]
+ public void Prevent_code_reuse() {
+ var date = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ var usedCodesManager = new UsedCodesManager();
+ var authenticator = new TimeAuthenticator(() => date, usedCodeManager: usedCodesManager);
+ var secret = Authenticator.GenerateKey();
+ var code = authenticator.GetCode(secret);
+
+ Assert.IsTrue(authenticator.CheckCode(secret, code));
+ Assert.IsFalse(authenticator.CheckCode(secret, code));
+ }
+
// Test Vectors from http://tools.ietf.org/html/rfc6238#appendix-B have all length 8. We want a length of 6.
// This Test Vectors are from a Ruby implementation. They work with the Google Authentificator app.
[TestCase("DRMK64PPMMC7TDZF", "2013-12-04 18:33:01 +0100", "661188")]
diff --git a/TwoStepsAuthenticator.UnitTests/UsedCodesManagerTests.cs b/TwoStepsAuthenticator.UnitTests/UsedCodesManagerTests.cs
index 1138f54..7b39650 100644
--- a/TwoStepsAuthenticator.UnitTests/UsedCodesManagerTests.cs
+++ b/TwoStepsAuthenticator.UnitTests/UsedCodesManagerTests.cs
@@ -14,23 +14,23 @@ namespace TwoStepsAuthenticator.UnitTests {
public void Can_add_codes() {
var manager = new UsedCodesManager();
- Assert.IsFalse(manager.IsCodeUsed(42uL, "def"));
- manager.AddCode(42uL, "def");
- Assert.IsTrue(manager.IsCodeUsed(42uL, "def"));
+ Assert.IsFalse(manager.IsCodeUsed(42L, "def"));
+ manager.AddCode(42L, "def");
+ Assert.IsTrue(manager.IsCodeUsed(42L, "def"));
}
}
internal class MockUsedCodesManager : IUsedCodesManager {
- public ulong? LastChallenge { get; private set; }
+ public long? LastChallenge { get; private set; }
public string LastCode { get; private set; }
- public void AddCode(ulong challenge, string code) {
+ public void AddCode(long challenge, string code) {
this.LastChallenge = challenge;
this.LastCode = code;
}
- public bool IsCodeUsed(ulong challenge, string code) {
+ public bool IsCodeUsed(long challenge, string code) {
return false;
}
}
diff --git a/TwoStepsAuthenticator/Authenticator.cs b/TwoStepsAuthenticator/Authenticator.cs
index 4415e77..eea3612 100644
--- a/TwoStepsAuthenticator/Authenticator.cs
+++ b/TwoStepsAuthenticator/Authenticator.cs
@@ -12,7 +12,6 @@ namespace TwoStepsAuthenticator
private static readonly RNGCryptoServiceProvider Random = new RNGCryptoServiceProvider(); // Is Thread-Safe
private static readonly int KeyLength = 16;
private static readonly string AvailableKeyChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
- internal static readonly Lazy<IUsedCodesManager> DefaultUsedCodeManager = new Lazy<IUsedCodesManager>(() => new UsedCodesManager());
public static string GenerateKey() {
var keyChars = new char[KeyLength];
diff --git a/TwoStepsAuthenticator/CounterAuthenticator.cs b/TwoStepsAuthenticator/CounterAuthenticator.cs
index fffae73..ae67ee5 100644
--- a/TwoStepsAuthenticator/CounterAuthenticator.cs
+++ b/TwoStepsAuthenticator/CounterAuthenticator.cs
@@ -11,14 +11,12 @@ namespace TwoStepsAuthenticator {
/// </summary>
public class CounterAuthenticator : Authenticator {
private readonly int WindowSize;
- private readonly IUsedCodesManager UsedCodeManager;
- public CounterAuthenticator(int windowSize = 10, IUsedCodesManager usedCodeManager = null) {
+ public CounterAuthenticator(int windowSize = 10) {
if (windowSize <= 0) {
throw new ArgumentException("look-ahead window size must be positive");
}
- this.UsedCodeManager = (usedCodeManager == null) ? Authenticator.DefaultUsedCodeManager.Value : usedCodeManager;
this.WindowSize = windowSize;
}
@@ -59,11 +57,9 @@ namespace TwoStepsAuthenticator {
for (uint i = 0; i <= WindowSize; i++) {
ulong checkCounter = counter + i;
- if (ConstantTimeEquals(GetCode(secret, checkCounter), code) && !UsedCodeManager.IsCodeUsed(checkCounter, code)) {
+ if (ConstantTimeEquals(GetCode(secret, checkCounter), code)) {
codeMatch = true;
successfulSequenceNumber = checkCounter;
-
- UsedCodeManager.AddCode(successfulSequenceNumber, code);
}
}
diff --git a/TwoStepsAuthenticator/IUsedCodesManager.cs b/TwoStepsAuthenticator/IUsedCodesManager.cs
index 461975c..8ff1fe3 100644
--- a/TwoStepsAuthenticator/IUsedCodesManager.cs
+++ b/TwoStepsAuthenticator/IUsedCodesManager.cs
@@ -12,7 +12,7 @@ namespace TwoStepsAuthenticator {
/// </summary>
/// <param name="challenge">Used Challenge</param>
/// <param name="code">Used Code</param>
- void AddCode(ulong challenge, string code);
+ void AddCode(long timestamp, string code);
/// <summary>
/// Checks if code was previously used.
@@ -20,6 +20,6 @@ namespace TwoStepsAuthenticator {
/// <param name="challenge">Used Challenge</param>
/// <param name="code">Used Code</param>
/// <returns></returns>
- bool IsCodeUsed(ulong challenge, string code);
+ bool IsCodeUsed(long timestamp, string code);
}
}
diff --git a/TwoStepsAuthenticator/TimeAuthenticator.cs b/TwoStepsAuthenticator/TimeAuthenticator.cs
index f46b6d0..572d736 100644
--- a/TwoStepsAuthenticator/TimeAuthenticator.cs
+++ b/TwoStepsAuthenticator/TimeAuthenticator.cs
@@ -10,13 +10,15 @@ namespace TwoStepsAuthenticator {
/// Implementation of rfc6238 Time-Based One-Time Password Algorithm
/// </summary>
public class TimeAuthenticator : Authenticator {
+ private static readonly Lazy<IUsedCodesManager> DefaultUsedCodeManager = new Lazy<IUsedCodesManager>(() => new UsedCodesManager());
+
private readonly Func<DateTime> NowFunc;
private readonly IUsedCodesManager UsedCodeManager;
private readonly int IntervalSeconds;
public TimeAuthenticator(Func<DateTime> nowFunc = null, IUsedCodesManager usedCodeManager = null, int intervalSeconds = 30) {
this.NowFunc = (nowFunc == null) ? () => DateTime.Now : nowFunc;
- this.UsedCodeManager = (usedCodeManager == null) ? Authenticator.DefaultUsedCodeManager.Value : usedCodeManager;
+ this.UsedCodeManager = (usedCodeManager == null) ? DefaultUsedCodeManager.Value : usedCodeManager;
this.IntervalSeconds = intervalSeconds;
}
@@ -66,7 +68,7 @@ namespace TwoStepsAuthenticator {
var codeMatch = false;
for (int i = -2; i <= 1; i++) {
var checkTime = baseTime.AddSeconds(IntervalSeconds * i);
- ulong checkInterval = (ulong)GetInterval(checkTime);
+ var checkInterval = GetInterval(checkTime);
if (ConstantTimeEquals(GetCode(secret, checkTime), code) && !UsedCodeManager.IsCodeUsed(checkInterval, code)) {
codeMatch = true;
diff --git a/TwoStepsAuthenticator/UsedCodesManager.cs b/TwoStepsAuthenticator/UsedCodesManager.cs
index 6ffd6cf..13b3d61 100644
--- a/TwoStepsAuthenticator/UsedCodesManager.cs
+++ b/TwoStepsAuthenticator/UsedCodesManager.cs
@@ -14,15 +14,15 @@ namespace TwoStepsAuthenticator
{
internal sealed class UsedCode
{
- public UsedCode(ulong challenge, String code)
+ public UsedCode(long timestamp, String code)
{
this.UseDate = DateTime.Now;
this.Code = code;
- this.ChallengeValue = challenge;
+ this.Timestamp = timestamp;
}
internal DateTime UseDate { get; private set; }
- internal ulong ChallengeValue { get; private set; }
+ internal long Timestamp { get; private set; }
internal String Code { get; private set; }
public override bool Equals(object obj)
@@ -32,15 +32,15 @@ namespace TwoStepsAuthenticator
}
var other = obj as UsedCode;
- return (other != null) ? this.Code.Equals(other.Code) && this.ChallengeValue.Equals(other.ChallengeValue) : false;
+ return (other != null) ? this.Code.Equals(other.Code) && this.Timestamp.Equals(other.Timestamp) : false;
}
public override string ToString()
{
- return String.Format("{0}: {1}", ChallengeValue, Code);
+ return String.Format("{0}: {1}", Timestamp, Code);
}
public override int GetHashCode()
{
- return Code.GetHashCode() + ChallengeValue.GetHashCode() * 17;
+ return Code.GetHashCode() + Timestamp.GetHashCode() * 17;
}
}
@@ -75,12 +75,12 @@ namespace TwoStepsAuthenticator
}
}
- public void AddCode(ulong challenge, String code)
+ public void AddCode(long timestamp, String code)
{
try {
rwlock.AcquireWriterLock(lockingTimeout);
- codes.Enqueue(new UsedCode(challenge, code));
+ codes.Enqueue(new UsedCode(timestamp, code));
}
finally
{
@@ -88,13 +88,13 @@ namespace TwoStepsAuthenticator
}
}
- public bool IsCodeUsed(ulong challenge, String code)
+ public bool IsCodeUsed(long timestamp, String code)
{
try
{
rwlock.AcquireReaderLock(lockingTimeout);
- return codes.Contains(new UsedCode(challenge, code));
+ return codes.Contains(new UsedCode(timestamp, code));
}
finally
{