Skip to content

Commit

Permalink
Pad g, A and B values according to RFC5054, #44.
Browse files Browse the repository at this point in the history
  • Loading branch information
yallie committed May 23, 2018
1 parent 195debe commit 5f2fbdc
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 11 deletions.
6 changes: 4 additions & 2 deletions SrpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,12 @@ public SrpSession DeriveSession(string clientSecretEphemeral, string serverPubli
// g — A generator modulo N
// k — Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6)
// H — One-way hash function
// PAD — Pad the number to have the same number of bytes as N
var N = Parameters.N;
var g = Parameters.G;
var k = Parameters.K;
var H = Parameters.H;
var PAD = Parameters.PAD;

// a — Secret ephemeral value
// B — Public ephemeral value
Expand All @@ -136,8 +138,8 @@ public SrpSession DeriveSession(string clientSecretEphemeral, string serverPubli
throw new SecurityException("The server sent an invalid public ephemeral");
}

// u = H(A, B)
var u = H(A, B);
// u = H(PAD(A), PAD(B))
var u = H(PAD(A), PAD(B));

// S = (B - kg^x) ^ (a + ux)
var S = (B - (k * (g.ModPow(x, N)))).ModPow(a + (u * x), N);
Expand Down
13 changes: 13 additions & 0 deletions SrpInteger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,26 @@ private static string NormalizeWhitespace(string hexNumber) =>
/// </summary>
public static SrpInteger Zero { get; } = new SrpInteger();

/// <summary>
/// Gets or sets the value.
/// </summary>
private BigInteger Value { get; set; }

/// <summary>
/// Gets the hexadecimal length.
/// </summary>
internal int? HexLength { get; private set; }

/// <summary>
/// Pads the value to the specified new hexadecimal length.
/// </summary>
/// <param name="newLength">The new length.</param>
public SrpInteger Pad(int newLength) => new SrpInteger
{
Value = Value,
HexLength = newLength,
};

/// <summary>
/// Generates the random integer number.
/// </summary>
Expand Down
28 changes: 21 additions & 7 deletions SrpParameters.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Security.Cryptography;
using System;
using System.Security.Cryptography;

namespace Zyan.Communication.Security.SecureRemotePassword
{
Expand All @@ -14,7 +15,9 @@ public SrpParameters()
{
N = SrpInteger.FromHex(LargeSafePrime);
G = SrpInteger.FromHex("02");
PaddedLength = N.HexLength.Value;
Hasher = new SrpHash<SHA256>();
PAD = i => i.Pad(PaddedLength);
}

/// <summary>
Expand All @@ -23,8 +26,8 @@ public SrpParameters()
/// <typeparam name="T"></typeparam>
/// <param name="largeSafePrime">Large safe prime number N (hexadecimal).</param>
/// <param name="generator">The generator value modulo N (hexadecimal).</param>
/// <param name="padGenerator">If true, pad generator to the same length as N, as required by RFC5054 (incompatible with secure-remote-password npm module).</param>
public static SrpParameters Create<T>(string largeSafePrime = null, string generator = null, bool padGenerator = false)
/// <param name="paddedLength">The hexadecimal length of N and g.</param>
public static SrpParameters Create<T>(string largeSafePrime = null, string generator = null, int? paddedLength = null)
where T : HashAlgorithm
{
var result = new SrpParameters
Expand All @@ -35,16 +38,17 @@ public static SrpParameters Create<T>(string largeSafePrime = null, string gener
if (largeSafePrime != null)
{
result.N = SrpInteger.FromHex(largeSafePrime);
result.PaddedLength = result.N.HexLength.Value;
}

if (generator != null)
{
result.G = SrpInteger.FromHex(generator);
}

if (padGenerator)
if (paddedLength.HasValue)
{
result.G = new SrpInteger(result.G, result.N.HexLength);
result.PaddedLength = paddedLength.Value;
}

return result;
Expand All @@ -63,6 +67,11 @@ 03CE5329 9CCC041C 7BC308D8 2A5698F3 A8D0C382 71AE35F8 E9DBFBB6
94B5C803 D89F7AE4 35DE236D 525F5475 9B65E372 FCD68EF2 0FA7111F
9E4AFF73";

/// <summary>
/// Gets or sets the length of the padded N and g values.
/// </summary>
public int PaddedLength { get; set; }

/// <summary>
/// Gets or sets the large safe prime number (N = 2q+1, where q is prime).
/// </summary>
Expand All @@ -83,15 +92,20 @@ 94B5C803 D89F7AE4 35DE236D 525F5475 9B65E372 FCD68EF2 0FA7111F
/// </summary>
public SrpHash H => Hasher.HashFunction;

/// <summary>
/// Pads the specified integer value.
/// </summary>
public Func<SrpInteger, SrpInteger> PAD { get; }

/// <summary>
/// Gets the hash size in bytes.
/// </summary>
public int HashSizeBytes => Hasher.HashSizeBytes;

/// <summary>
/// Gets the multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6).
/// Gets the multiplier parameter: k = H(N, g) in SRP-6a (k = 3 for legacy SRP-6).
/// </summary>
public SrpInteger K => H(N, G);
public SrpInteger K => H(N, PAD(G));

/// <inheritdoc/>
public override string ToString() => $"SrpParameters.Create<{Hasher.AlgorithmName}>(\"{N.ToHex()}\", \"{G.ToHex()}\")";
Expand Down
6 changes: 4 additions & 2 deletions SrpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@ public SrpSession DeriveSession(string serverSecretEphemeral, string clientPubli
// g — A generator modulo N
// k — Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6)
// H — One-way hash function
// PAD — Pad the number to have the same number of bytes as N
var N = Parameters.N;
var g = Parameters.G;
var k = Parameters.K;
var H = Parameters.H;
var PAD = Parameters.PAD;

// b — Secret ephemeral values
// A — Public ephemeral values
Expand All @@ -91,8 +93,8 @@ public SrpSession DeriveSession(string serverSecretEphemeral, string clientPubli
throw new SecurityException("The client sent an invalid public ephemeral");
}

// u = H(A, B)
var u = H(A, B);
// u = H(PAD(A), PAD(B))
var u = H(PAD(A), PAD(B));

// S = (Av^u) ^ b (computes session key)
var S = (A * v.ModPow(u, N)).ModPow(b, N);
Expand Down

0 comments on commit 5f2fbdc

Please sign in to comment.