Skip to content

Commit

Permalink
totp
Browse files Browse the repository at this point in the history
  • Loading branch information
FuzzySecurity committed Aug 30, 2022
1 parent 9c2f31f commit 1f87371
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 0 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 631,58 @@ C:\> PickmansModel.exe -p testPipe -a Hello123!
[Client Sending] : Pickman had promised to shew me the place, and heaven knows he had done it. He led me out of that tangle of alleys in another direction, it seems, for when we sighted a lamp post we were in a half-familiar street with monotonous rows of mingled tenement blocks and old houses. Charter Street, it turned out to be, but I was too flustered to notice just where we hit it.
```

### TOTP-Gen

`totp-gen` is a small POC which demonstrates time-based one-time password (TOTP) generation in C#. This POC specifically gets `DateTime.UtcNow` and uses that as a `Key` value to initialize `HMACSHA256`. The `HMACSHA256` object is then used to hash a `String` based seed and generate a numeric TOTP value.

This is mostly to be used as a reference for me so I can strip out the generator if needed and integrate it into other tools (e.g., an extra layer of auth for an encrypted comms channel). The only required functions are `generateTOTP` and `validateTOTP` in `hTOTP.cs`.

Notes:
- TOTP's are scoped to a full `UtcNow` minute.
- It is of course possible to adjust the timespan during which a code is valid but generating a new one every minute seems reasonable.
- It would be easy, and recommended, that a forgiveness mechanic is added to `generateTOTP` so it calculates the current and previous TOTP in case an authentication code is generated before the minute rolls over and is received during the next minute.


```
C:\>totp_gen.exe -s HelloWorld
_ _
| |_ ___| |_ _ __ ___ __ _ ___ ___
| _/ _ \ _| '_ \___/ _` / -_) \
\__\___/\__| .__/ \__, \___|_||_|
|_| |___/
[ ] TOTP valid for 30 seconds
[>] TOTP code --> 1447475300
C:\>totp_gen.exe -s Jumanji
_ _
| |_ ___| |_ _ __ ___ __ _ ___ ___
| _/ _ \ _| '_ \___/ _` / -_) \
\__\___/\__| .__/ \__, \___|_||_|
|_| |___/
[ ] TOTP valid for 23 seconds
[>] TOTP code --> 587402414
C:\>totp_gen.exe -s Jumanji -c 587402414
_ _
| |_ ___| |_ _ __ ___ __ _ ___ ___
| _/ _ \ _| '_ \___/ _` / -_) \
\__\___/\__| .__/ \__, \___|_||_|
|_| |___/
[ ] TOTP code is valid
C:\>totp_gen.exe -s Jumanji -c 999902414
_ _
| |_ ___| |_ _ __ ___ __ _ ___ ___
| _/ _ \ _| '_ \___/ _` / -_) \
\__\___/\__| .__/ \__, \___|_||_|
|_| |___/
[!] TOTP code is invalid
```

## Windows API

### GetAPISetMapping
Expand Down
13 changes: 13 additions & 0 deletions totp-gen/totp-gen.sln
Original file line number Diff line number Diff line change
@@ -0,0 1,13 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "totp-gen", "totp-gen\totp-gen.csproj", "{FA1D9A36-415A-4855-8C01-54B6E9FC6965}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FA1D9A36-415A-4855-8C01-54B6E9FC6965}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA1D9A36-415A-4855-8C01-54B6E9FC6965}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
67 changes: 67 additions & 0 deletions totp-gen/totp-gen/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 1,67 @@
using System;
using CommandLine;

namespace totp_gen
{
internal class Program
{
public static void generateTOTP(String sSeed)
{
hTOTP.TOTP oTotp = hTOTP.generateTOTP(sSeed);
Console.WriteLine("[ ] TOTP valid for {0} seconds", oTotp.Seconds);
Console.WriteLine("[>] TOTP code --> {0}", oTotp.Code);
}

public static void checkTOTP(String sSeed, UInt32 iCode)
{
Boolean bTOTP = hTOTP.validateTOTP(sSeed, iCode);
if (bTOTP)
{
Console.WriteLine("[ ] TOTP code is valid");
}
else
{
Console.WriteLine("[!] TOTP code is invalid");
}
}

class ArgOptions
{
[Option("s", "seed")]
public String Seed { get; set; }

[Option("c", "code")]
public UInt32 Code { get; set; }
}

public static void Main(string[] args)
{
hTOTP.printBanner();

ArgOptions ArgOptions = new ArgOptions();
if (CommandLineParser.Default.ParseArguments(args, ArgOptions))
{
if (!String.IsNullOrEmpty(ArgOptions.Seed))
{
if (ArgOptions.Code != 0)
{
checkTOTP(ArgOptions.Seed, ArgOptions.Code);
}
else
{
generateTOTP(ArgOptions.Seed);
}
}
else
{
hTOTP.getHelp();
}

}
else
{
hTOTP.getHelp();
}
}
}
}
35 changes: 35 additions & 0 deletions totp-gen/totp-gen/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("totp_gen")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("totp_gen")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("FA1D9A36-415A-4855-8C01-54B6E9FC6965")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
78 changes: 78 additions & 0 deletions totp-gen/totp-gen/hTOTP.cs
Original file line number Diff line number Diff line change
@@ -0,0 1,78 @@
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;

namespace totp_gen
{
public class hTOTP
{
// Fluff
//===================================================
public static void printBanner()
{
Console.WriteLine(@" _ _ ");
Console.WriteLine(@" | |_ ___| |_ _ __ ___ __ _ ___ ___ ");
Console.WriteLine(@" | _/ _ \ _| '_ \___/ _` / -_) \ ");
Console.WriteLine(@" \__\___/\__| .__/ \__, \___|_||_|");
Console.WriteLine(@" |_| |___/ " "\n");
}

public static void getHelp()
{
Console.WriteLine("-=Flags=-\n");
Console.WriteLine("-s/--seed String, secret seed for the TOTP generator");
Console.WriteLine("-c/--code UInt32, TOTP code to validate");
Console.WriteLine("\n-=Usage=-\n");
Console.WriteLine("// Generate TOTP from seed");
Console.WriteLine("totp_gen.exe -s HelloWorld\n");
Console.WriteLine("// Validate TOTP code");
Console.WriteLine("totp_gen.exe -s HelloWorld -c 1766951436");
}

// Structs
//===================================================
[StructLayout(LayoutKind.Sequential)]
public struct TOTP
{
public UInt32 Seconds;
public UInt32 Code;
}

// Functions
//===================================================
public static TOTP generateTOTP(String sSeed)
{
// Create return object
TOTP oTOTP = new hTOTP.TOTP();

// Get DatTime
DateTime dtNow = DateTime.UtcNow;
oTOTP.Seconds = (UInt32)(60 - dtNow.Second);

// Subtract seconds from current time
dtNow = dtNow.AddSeconds(-dtNow.Second);

// Init HMAC with DateTime key & compute hash with seed value
HMACSHA256 hmac = new HMACSHA256(Encoding.ASCII.GetBytes(dtNow.ToString(CultureInfo.InvariantCulture)));
Byte[] bHash = hmac.ComputeHash(Encoding.ASCII.GetBytes(sSeed));

// Get TOTP
UInt32 iOffset = (UInt32)bHash[bHash.Length - 1] & 0xF;
oTOTP.Code = (UInt32)((bHash[iOffset] & 0x7F) << 24 | (bHash[iOffset 1] & 0xFF) << 16 | (bHash[iOffset 2] & 0xFF) << 8 | (bHash[iOffset 3] & 0xFF) % 1000000);

// Return TOTP
return oTOTP;
}

public static Boolean validateTOTP(String sSeed, UInt32 iCode)
{
// Get TOTP for seed
TOTP oTOTP = generateTOTP(sSeed);

// Check if code is valid
return (oTOTP.Code == iCode);
}
}
}
4 changes: 4 additions & 0 deletions totp-gen/totp-gen/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommandLineParser" version="1.9.3.15" targetFramework="net48" />
</packages>
51 changes: 51 additions & 0 deletions totp-gen/totp-gen/totp-gen.csproj
Original file line number Diff line number Diff line change
@@ -0,0 1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{FA1D9A36-415A-4855-8C01-54B6E9FC6965}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>totp_gen</RootNamespace>
<AssemblyName>totp_gen</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="CommandLine, Version=1.9.3.15, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\CommandLineParser.1.9.3.15\lib\CommandLine.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="hTOTP.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->

</Project>

0 comments on commit 1f87371

Please sign in to comment.