Skip to content

Commit

Permalink
Merge pull request #66 from caterina-novak/master
Browse files Browse the repository at this point in the history
Issue #65  ValidateTwoFactorPin always returns false, if the secretKey parameter is base32 encoded string - fixed
  • Loading branch information
ahwm authored Jul 9, 2021
2 parents b694ce7 + b759503 commit ba2c632
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 168 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,11 @@ FakesAssemblies/
# Visual Studio 6 workspace options file
*.opt
.vscode/
.idea/.idea.Google.Authenticator/.idea/.name
.idea/.idea.Google.Authenticator/.idea/codeStyles/codeStyleConfig.xml
.idea/.idea.Google.Authenticator/.idea/encodings.xml
.idea/.idea.Google.Authenticator/.idea/indexLayout.xml
.idea/.idea.Google.Authenticator/.idea/projectSettingsUpdater.xml
.idea/.idea.Google.Authenticator/.idea/vcs.xml
.idea/.idea.Google.Authenticator/.idea/workspace.xml
.idea/config/applicationhost.config
38 changes: 28 additions & 10 deletions Google.Authenticator.Tests/AuthCodeTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using Xunit;
using System.Text;
using Shouldly;
using Xunit;

namespace Google.Authenticator.Tests
{
Expand All @@ -9,17 +9,35 @@ public class AuthCodeTest
[Fact]
public void BasicAuthCodeTest()
{
string secretKey = "PJWUMZKAUUFQKJBAMD6VGJ6RULFVW4ZH";
string expected = "551508";
var secretKey = "PJWUMZKAUUFQKJBAMD6VGJ6RULFVW4ZH";
var expected = "551508";

var tfa = new TwoFactorAuthenticator();

TwoFactorAuthenticator tfa = new TwoFactorAuthenticator();

long currentTime = 1416643820;
var currentTime = 1416643820;

// I actually think you are supposed to divide the time by 30 seconds? Maybe need an overload that takes a DateTime?
// I actually think you are supposed to divide the time by 30 seconds?
// Maybe need an overload that takes a DateTime?
var actual = tfa.GeneratePINAtInterval(secretKey, currentTime, 6);

actual.ShouldBe(expected);
actual.ShouldBe(expected);
}

[Fact]
public void Base32AuthCodeTest()
{
var secretKey = Base32Encoding.ToString(Encoding.UTF8.GetBytes("PJWUMZKAUUFQKJBAMD6VGJ6RULFVW4ZH"));
var expected = "551508";

var tfa = new TwoFactorAuthenticator();

var currentTime = 1416643820;

// I actually think you are supposed to divide the time by 30 seconds?
// Maybe need an overload that takes a DateTime?
var actual = tfa.GeneratePINAtInterval(secretKey, currentTime, 6, true);

actual.ShouldBe(expected);
}
}
}
}
19 changes: 12 additions & 7 deletions Google.Authenticator.Tests/Google.Authenticator.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net452</TargetFrameworks>
<TargetFrameworks>netcoreapp3.0;net452;net5</TargetFrameworks>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="Shouldly" Version="3.0.2" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.0.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Google.Authenticator\Google.Authenticator.csproj" />
</ItemGroup>

</Project>
</Project>
9 changes: 7 additions & 2 deletions Google.Authenticator.Tests/QRCodeTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using Xunit;
using Shouldly;

Expand All @@ -10,7 +9,13 @@ public class QRCodeTest
public void CanGenerateQRCode()
{
var subject = new TwoFactorAuthenticator();
var setupCodeInfo = subject.GenerateSetupCode("issuer","a@b.com","secret", false, 2);
var setupCodeInfo = subject.GenerateSetupCode(
"issuer",
"a@b.com",
"secret",
false,
2);

setupCodeInfo.QrCodeSetupImageUrl.ShouldNotBeNull();
}
}
Expand Down
49 changes: 24 additions & 25 deletions Google.Authenticator/Base32Encoding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,39 @@ public static byte[] ToBytes(string input)
{
if (string.IsNullOrEmpty(input))
{
throw new ArgumentNullException("input");
throw new ArgumentNullException(nameof(input));
}

input = input.TrimEnd('='); //remove padding characters
int byteCount = input.Length * 5 / 8; //this must be TRUNCATED
byte[] returnArray = new byte[byteCount];
var byteCount = input.Length * 5 / 8; //this must be TRUNCATED
var returnArray = new byte[byteCount];

byte curByte = 0, bitsRemaining = 8;
int mask = 0, arrayIndex = 0;
int mask, arrayIndex = 0;

foreach (char c in input)
foreach (var c in input)
{
int cValue = CharToValue(c);
var cValue = CharToValue(c);

if (bitsRemaining > 5)
{
mask = cValue << (bitsRemaining - 5);
curByte = (byte)(curByte | mask);
curByte = (byte) (curByte | mask);
bitsRemaining -= 5;
}
else
{
mask = cValue >> (5 - bitsRemaining);
curByte = (byte)(curByte | mask);
curByte = (byte) (curByte | mask);
returnArray[arrayIndex++] = curByte;
curByte = (byte)(cValue << (3 + bitsRemaining));
curByte = (byte) (cValue << (3 + bitsRemaining));
bitsRemaining += 3;
}
}

//if we didn't end with a full byte
if (arrayIndex != byteCount)
{
returnArray[arrayIndex] = curByte;
}

return returnArray;
}
Expand All @@ -64,29 +62,29 @@ public static string ToString(byte[] input)
{
if (input == null || input.Length == 0)
{
throw new ArgumentNullException("input");
throw new ArgumentNullException(nameof(input));
}

int charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
char[] returnArray = new char[charCount];
var charCount = (int) Math.Ceiling(input.Length / 5d) * 8;
var returnArray = new char[charCount];

byte nextChar = 0, bitsRemaining = 5;
int arrayIndex = 0;
var arrayIndex = 0;

foreach (byte b in input)
foreach (var b in input)
{
nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining)));
nextChar = (byte) (nextChar | (b >> (8 - bitsRemaining)));
returnArray[arrayIndex++] = ValueToChar(nextChar);

if (bitsRemaining < 4)
{
nextChar = (byte)((b >> (3 - bitsRemaining)) & 31);
nextChar = (byte) ((b >> (3 - bitsRemaining)) & 31);
returnArray[arrayIndex++] = ValueToChar(nextChar);
bitsRemaining += 5;
}

bitsRemaining -= 3;
nextChar = (byte)((b << bitsRemaining) & 31);
nextChar = (byte) ((b << bitsRemaining) & 31);
}

//if we didn't end with a full char
Expand All @@ -101,41 +99,42 @@ public static string ToString(byte[] input)

private static int CharToValue(char c)
{
int value = (int)c;
var value = (int) c;

//65-90 == uppercase letters
if (value < 91 && value > 64)
{
return value - 65;
}

//50-55 == numbers 2-7
if (value < 56 && value > 49)
{
return value - 24;
}

//97-122 == lowercase letters
if (value < 123 && value > 96)
{
return value - 97;
}

throw new ArgumentException("Character is not a Base32 character.", "c");
throw new ArgumentException("Character is not a Base32 character.", nameof(c));
}

private static char ValueToChar(byte b)
{
if (b < 26)
{
return (char)(b + 65);
return (char) (b + 65);
}

if (b < 32)
{
return (char)(b + 24);
return (char) (b + 24);
}

throw new ArgumentException("Byte is not a value Base32 value.", "b");
throw new ArgumentException("Byte is not a value Base32 value.", nameof(b));
}

}
}
12 changes: 8 additions & 4 deletions Google.Authenticator/Google.Authenticator.csproj
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net45</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net45;net5</TargetFrameworks>
<Product>Google Authenticator Two-Factor</Product>
<Title>Google Authenticator Two-Factor Authentication Library</Title>
<Description>Google Authenticator Two-Factor Authentication Library (Not officially affiliated with Google.)</Description>
<Authors>Brandon Potter</Authors>
<Company>Brandon Potter</Company>
<Version>2.1.1</Version>
<Version>2.2.0</Version>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/BrandonPotter/GoogleAuthenticator</PackageProjectUrl>
<PackageId>GoogleAuthenticator</PackageId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="QRCoder" Version="1.3.9" />
<PackageReference Include="QRCoder" Version="1.4.1" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

Expand All @@ -30,11 +30,15 @@
<DefineConstants>NET45;NETFULL</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net5'">
<DefineConstants>NET5_0;NETCOREAPP</DefineConstants>
</PropertyGroup>

<PropertyGroup>
<AllowedOutputExtensionsInPackageBuildOutputFolder>
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
</AllowedOutputExtensionsInPackageBuildOutputFolder>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AssemblyVersion>2.0.1.0</AssemblyVersion>
</PropertyGroup>
</Project>
</Project>
7 changes: 1 addition & 6 deletions Google.Authenticator/SetupCode.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Google.Authenticator
namespace Google.Authenticator
{
public class SetupCode
{
Expand Down
Loading

0 comments on commit ba2c632

Please sign in to comment.