Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #65 ValidateTwoFactorPin always returns false, if the secretKey parameter is base32 encoded string - fixed #66

Merged
merged 4 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

[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","[email protected]","secret", false, 2);
var setupCodeInfo = subject.GenerateSetupCode(
"issuer",
"[email protected]",
"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));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't remove {} here :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done :)

}

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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't remove {} here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done :)

}

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));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't remove {} here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't remove {} here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

{
return value - 65;
}

//50-55 == numbers 2-7
if (value < 56 && value > 49)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't remove {} here

{
return value - 24;
}

//97-122 == lowercase letters
if (value < 123 && value > 96)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't remove {} here

{
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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't remove {} here

{
return (char)(b + 65);
return (char) (b + 65);
}

if (b < 32)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't remove {} here

{
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