3

I finally finished the implementation of the SRP protocol in delphi! Using the openssl library to calculate the hash and Bignum.

The implementation at the end is not complicated. but I have come in doubt:

1) I can use random pair N, g. N 4096 bit is safe enough?

2) K, as RFC 5054, is a strong session key, but has a length of 768 bytes with N to 4906 bits. So how can I correctly use this session key with AES256?

3) Finally, is there any way to test if the implementation I wrote it works as it should? Is there anyone who can give me advice?

Place the code, taking into account that it is not yet optimized, the type N, G may be of class var.

Thanks in advance to all.

type

  TSRP = class
  public
    class procedure CreateVerifierKey( const AIdentity, APassword: TIdBytes; var ASalt, AVerifierKey: TIdBytes );
    class procedure ServerValues( const ASalt, AVerifierKey: TIdBytes; var APrivateValue, APublicValue: TIdBytes );
    class procedure IdentityValues( var APrivateValue, APublicValue: TIdBytes );
    class function ServerKey( const AServerPrivateValue, AServerPublicValue, AVerifierKey, AIdentityPublicValue: TIdBytes ): TIdBytes;
    class function IdentityKey( const AIdentity, APassword, AIdentityPrivateValue, AIdentityPublicValue, ASalt, AServerPublicValue, AVerifierKey: TIdBytes ): TIdBytes;
    class function VerifierMessage( const AUserName: String; const ASalt, AServerPublicValue, AIdentityPublicValue, AKey: TIdBytes ): TIdBytes;
  end;

{ TSRP }

class procedure TSRP.CreateVerifierKey( const AIdentity, APassword: TIdBytes; var ASalt, AVerifierKey: TIdBytes );
var
  N: PBIGNUM;
  G: PBIGNUM;
  S: PBIGNUM;
  X: PBIGNUM;
  V: PBIGNUM;
  C: PBN_CTX;
begin
  S := BIGNUM;
  try
    BN_rand( S, 48, - 1, 0 );
    ASalt := BN_bytes( S );
  finally
    BN_free( S );
  end;
  X := BIGNUM( TIdSha512Hash.Digest( TIdBytes.From( ASalt ).Append( AIdentity ).Append( APassword ) ) );
  N := BIGNUM( TIdBase64.Decode( SRP_NG_4096_N ) );
  G := BIGNUM( [ 5 ] );
  C := BN_CTX_new;
  V := BN_new;
  BN_mod_exp( V, G, X, N, C );
  SetLength( AVerifierKey, TIdSha512Hash.Size );
  AVerifierKey := BN_bytes( V );
  BN_free( X );
  BN_free( N );
  BN_free( G );
  BN_free( V );
  BN_CTX_free( C );
end;

class procedure TSRP.ServerValues( const ASalt, AVerifierKey: TIdBytes; var APrivateValue, APublicValue: TIdBytes );
var
  G: PBIGNUM;
  N: PBIGNUM;
  K: PBIGNUM;
  B: PBIGNUM;
  R: PBIGNUM;
  A: PBIGNUM;
  V: PBIGNUM;
  C: PBN_CTX;
begin
  B := BIGNUM;
  BN_rand( B, 256, - 1, 0 );
  APrivateValue := BN_bytes( B );
  N := BIGNUM( TIdBase64.Decode( SRP_NG_4096_N ) );
  G := BIGNUM( [ 5 ] );
  K := BIGNUM( TIdSha512Hash.Digest( TIdBytes.From( BN_Bytes( N ) ).Append( BN_Bytes( G ) ) ) );
  R := BIGNUM;
  A := BIGNUM;
  V := BIGNUM;
  C := BN_CTX_new;
  BN_mul( R, K, BIGNUM( AVerifierKey ), C );
  BN_mod_exp( A, G, B, N, C );
  BN_add( V, R, A );
  APublicValue := BN_bytes( V );
  BN_free( V );
  BN_free( A );
  BN_free( R );
  BN_free( K );
  BN_free( G );
  BN_free( N );
  BN_free( B );
  BN_CTX_free( C );
end;

class procedure TSRP.IdentityValues( var APrivateValue, APublicValue: TIdBytes );
var
  N: PBIGNUM;
  G: PBIGNUM;
  B: PBIGNUM;
  A: PBIGNUM;
  C: PBN_CTX;
begin
  N := BIGNUM( TIdBase64.Decode( SRP_NG_4096_N ) );
  G := BIGNUM( [ 5 ] );
  B := BIGNUM;
  A := BIGNUM;
  BN_rand( B, 256, - 1, 0 );
  APrivateValue := BN_bytes( B );
  C := BN_CTX_new;
  BN_mod_exp( A, G, B, N, C );
  APublicValue := BN_bytes( A );
  BN_free( B );
  BN_free( A );
  BN_free( G );
  BN_free( N );
  BN_CTX_free( C );
end;

class function TSRP.ServerKey( const AServerPrivateValue, AServerPublicValue, AVerifierKey, AIdentityPublicValue: TIdBytes ): TIdBytes;
var
  N: PBIGNUM;
  G: PBIGNUM;
  A: PBIGNUM;
  B: PBIGNUM;
  U: PBIGNUM;
  V: PBIGNUM;
  T: PBIGNUM;
  J: PBIGNUM;
  R: PBIGNUM;
  C: PBN_CTX;
begin
  N := BIGNUM( TIdBase64.Decode( SRP_NG_4096_N ) );
  G := BIGNUM( [ 5 ] );
  A := BIGNUM( AIdentityPublicValue );
  B := BIGNUM( AServerPrivateValue );
  V := BIGNUM( AVerifierKey );
  U := BIGNUM( TIdSha512Hash.Digest( TIdBytes.From( AIdentityPublicValue ).Append( AServerPublicValue ) ) );
  T := BIGNUM;
  J := BIGNUM;
  R := BIGNUM;
  C := BN_CTX_new;
  BN_mod_exp( T, V, U, N, C );
  BN_mul( J, A, T, C );
  BN_mod_exp( R, J, B, N, C );
  Result := BN_bytes( R );
  BN_free( N );
  BN_free( G );
  BN_free( A );
  BN_free( B );
  BN_free( V );
  BN_free( U );
  BN_free( T );
  BN_free( J );
  BN_free( R );
  BN_CTX_free( C );
end;

class function TSRP.IdentityKey( const AIdentity, APassword, AIdentityPrivateValue, AIdentityPublicValue, ASalt, AServerPublicValue, AVerifierKey: TIdBytes ): TIdBytes;
var
  N: PBIGNUM;
  G: PBIGNUM;
  B: PBIGNUM;
  X: PBIGNUM;
  K: PBIGNUM;
  A: PBIGNUM;
  U: PBIGNUM;
  V: PBIGNUM;
  T: PBIGNUM;
  L: PBIGNUM;
  P: PBIGNUM;
  Q: PBIGNUM;
  R: PBIGNUM;
  C: PBN_CTX;
begin
  N := BIGNUM( TIdBase64.Decode( SRP_NG_4096_N ) );
  G := BIGNUM( [ 5 ] );
  B := BIGNUM( AServerPublicValue );
  X := BIGNUM( TIdSha512Hash.Digest( TIdBytes.From( ASalt ).Append( AIdentity ).Append( APassword ) ) );
  K := BIGNUM( TIdSha512Hash.Digest( BN_bytes( N ).Append( BN_bytes( G ) ) ) );
  A := BIGNUM( AIdentityPrivateValue );
  U := BIGNUM( TIdSha512Hash.Digest( TIdBytes.From( AIdentityPublicValue ).Append( AServerPublicValue ) ) );
  V := BIGNUM;
  T := BIGNUM;
  L := BIGNUM;
  P := BIGNUM;
  Q := BIGNUM;
  R := BIGNUM;
  C := BN_CTX_new;
  BN_mod_exp( V, G, X, N, C );
  BN_mul( T, V, K, C );
  BN_sub( L, B, T );
  BN_mul( P, U, X, C );
  BN_add( Q, A, P );
  BN_mod_exp( R, L, Q, N, C );
  Result := BN_bytes( R );
  BN_free( N );
  BN_free( G );
  BN_free( B );
  BN_free( X );
  BN_free( K );
  BN_free( A );
  BN_free( U );
  BN_free( V );
  BN_free( T );
  BN_free( L );
  BN_free( P );
  BN_free( Q );
  BN_free( R );
  BN_CTX_free( C );
end;


class function TSRP.VerifierMessage( const AUserName: String; const ASalt, AServerPublicValue, AIdentityPublicValue, AKey: TIdBytes ): TIdBytes;
var
  N: PBIGNUM;
  G: PBIGNUM;
  R: PBIGNUM;
  X: TIdBytes;
  C: PBN_CTX;
begin
  N := BIGNUM( TIdBase64.Decode( SRP_NG_4096_N ) );
  G := BIGNUM( [ 5 ] );
  C := BN_CTX_new;
  R := BIGNUM;
  BN_mul( R, G, N, C );
  X := BN_bytes( R );
  Result.Assign( TIdSha512Hash.Digest( TIdBytes.From( X ).Append( AUserName ).Append( ASalt ).Append( AServerPublicValue ).Append( AIdentityPublicValue ).Append( AKey ) ) );
  Result.Assign( TIdSha512Hash.Digest( TIdBytes.From( AIdentityPublicValue ).Append( Result ).Append( AKey ) ) );
  BN_free( N );
  BN_free( G );
  BN_free( R );
  BN_CTX_free( C );
  X.Clear;
end;

Screenshot

enter image description here

user3703876
  • 174
  • 12
  • 3
    Just a piece of advice: it is almost always a bad idea to roll your own crypto. OpenSSL already contains a SRP implementation so you can just use the bindings. If this is a learning exercise, carry on. –  Oct 28 '15 at 10:48
  • I know well that isn't a good idea. I need to secure my allowed client / server without necessarily having to use certificates signed by a CA. Although i may use the Self Signed certificates but not guarantee to MIM attacks. As there is still implement ready for use in Delphi, I must necessarily implement alone. But I accept it if there are other alternatives. – user3703876 Oct 28 '15 at 10:53
  • Anyone have any advice? :( – user3703876 Oct 28 '15 at 13:01
  • My advice is the same as Tibor's. You'll get this wrong. Use an extant implementation. – David Heffernan Oct 28 '15 at 20:05

0 Answers0