CryptoDSA.Mod 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. MODULE CryptoDSA; (** AUTHOR "G.F."; PURPOSE "Digital Signature Algorithm DSA"; *)
  2. IMPORT
  3. B := CryptoBigNumbers, SHA1 := CryptoSHA1, P := CryptoPrimes, U := CryptoUtils, Streams,
  4. Base64 := CryptoBase64, BIT;
  5. TYPE
  6. Number = B.BigNumber;
  7. Signature* = OBJECT
  8. VAR
  9. r- : Number;
  10. s- : Number;
  11. PROCEDURE & Init*( r, s: Number );
  12. BEGIN
  13. B.Copy( r, SELF.r );
  14. B.Copy( s, SELF.s )
  15. END Init;
  16. END Signature;
  17. Key* = OBJECT
  18. VAR
  19. name-: ARRAY 128 OF CHAR; (** Owner of this key. *)
  20. private-: BOOLEAN;
  21. p- : Number;
  22. q- : Number;
  23. g- : Number;
  24. y- : Number;
  25. inv, r : Number;
  26. PROCEDURE Sign*( CONST digest: ARRAY OF CHAR; len: INTEGER ): Signature;
  27. VAR m, xr, ss: Number; sig: Signature;
  28. BEGIN
  29. ASSERT( private );
  30. IF (len > q.len*4 ) OR (len > 50) THEN HALT( 102 ) END;
  31. B.AssignBin( m, digest, 0, len );
  32. xr := B.Mul( y, r );
  33. ss := B.Add( xr, m ); (* s := inv( k ) * (m + x*r) mod q *)
  34. IF B.Cmp( ss, q ) > 0 THEN ss := B.Sub( ss, q ) END;
  35. ss := B.ModMul( ss, inv, q );
  36. NEW( sig, r, ss );
  37. RETURN sig
  38. END Sign;
  39. PROCEDURE Verify*( CONST digest: ARRAY OF CHAR; dlen: INTEGER; sig: Signature ): BOOLEAN;
  40. VAR
  41. u, v, w, t1, t2: Number;
  42. BEGIN
  43. ASSERT( ~private );
  44. IF B.Cmp( sig.r, q ) >= 0 THEN RETURN FALSE END;
  45. IF B.Cmp( sig.s, q ) >= 0 THEN RETURN FALSE END;
  46. (* w = inv( s ) mod q *)
  47. w := B.ModInverse( sig.s, q );
  48. (* v = m * w mod q *)
  49. B.AssignBin( v, digest, 0, dlen );
  50. v := B.ModMul( v, w, q );
  51. (* u = r * w mod q *)
  52. u := B.ModMul( sig.r, w, q );
  53. (* v = (g^v * y^u mod p) mod q *)
  54. t1 := B.ModExp( g, v, p );
  55. t2 := B.ModExp( y, u, p);
  56. v := B.ModMul( t1, t2, p );
  57. v := B.Mod( v, q );
  58. RETURN B.Cmp( v, sig.r ) = 0;
  59. END Verify;
  60. END Key;
  61. VAR
  62. one: Number; (* constant *)
  63. PROCEDURE GenParams*( dsa: Key; bits: INTEGER; CONST seed: ARRAY OF CHAR );
  64. VAR
  65. randomseed, pfound: BOOLEAN;
  66. i, k, n, count: INTEGER;
  67. test, W, r0: Number;
  68. sbuf, buf, buf2, md: ARRAY 20 OF CHAR;
  69. h: SHA1.Hash;
  70. BEGIN
  71. IF bits < 512 THEN
  72. bits := 512;
  73. ELSE
  74. bits := (bits + 63) DIV 64 * 64;
  75. END;
  76. randomseed := LEN( seed ) < 20;
  77. IF ~randomseed THEN
  78. FOR i := 0 TO 19 DO sbuf[i] := seed[i] END;
  79. END;
  80. B.AssignInt( test, 1 );
  81. test.Shift( bits - 1 );
  82. NEW( h );
  83. pfound := FALSE;
  84. LOOP (* find q and p *)
  85. REPEAT (* find q *)
  86. IF randomseed THEN
  87. B.RandomBytes( sbuf, 0, 20 );
  88. END;
  89. buf := sbuf;
  90. buf2 := sbuf;
  91. (* precompute "SEED + 1" *)
  92. REPEAT
  93. DEC( i );
  94. buf[i] := CHR( ORD( buf[i] ) + 1);
  95. UNTIL (i = 0) OR (buf[i] # 0X );
  96. h.Initialize;
  97. h.Update( sbuf, 0, 20 );
  98. h.GetHash( md, 0 );
  99. h.Initialize;
  100. h.Update( buf, 0, 20 );
  101. h.GetHash( buf2, 0 );
  102. FOR i := 0 TO 19 DO (* md := md xor buf2*)
  103. md[ i ] := BIT.CXOR( md[ i ], buf2[ i ] );
  104. END;
  105. IF ORD( md[0] ) < 128 THEN
  106. md[0] := CHR( ORD( md[0] ) + 128 );
  107. END;
  108. IF ~ODD( ORD( md[19] ) ) THEN
  109. md[19] := CHR( ORD( md[19] ) + 1 );
  110. END;
  111. B.AssignBin( dsa.q, md, 0, 20 );
  112. UNTIL P.IsPrime( dsa.q, 50, randomseed );
  113. count := 0; n := bits DIV 160;
  114. LOOP (* find p *)
  115. B.AssignInt( W, 0 );
  116. (* now 'buf' contains "SEED + offset - 1" *)
  117. FOR k := 0 TO n DO
  118. (* obtain "SEED + offset + k" by incrementing: *)
  119. i := 20;
  120. REPEAT
  121. DEC( i );
  122. buf[i] := CHR( ORD( buf[i] ) + 1)
  123. UNTIL (i = 0) OR (buf[i] # 0X );
  124. h.Initialize;
  125. h.Update( buf, 0, 20 );
  126. h.GetHash( md, 0 );
  127. B.AssignBin( r0, md, 0, 20 );
  128. r0.Shift( 160*k ); W := B.Add( W, r0 );
  129. END;
  130. W.Mask( bits - 1);
  131. W := B.Add( W, test );
  132. B.Copy( dsa.q, r0 );
  133. r0.Shift( 1 );
  134. r0 := B.Mod( W, r0 );
  135. r0.Dec;
  136. dsa.p := B.Sub( W, r0 );
  137. IF B.Cmp( dsa.p, test ) >= 0 THEN
  138. IF P.IsPrime( dsa.p, 50, TRUE ) THEN
  139. pfound := TRUE;
  140. EXIT;
  141. END;
  142. END;
  143. INC( count );
  144. IF count >= 4096 THEN EXIT END;
  145. END; (* find p *)
  146. IF pfound THEN EXIT END;
  147. END; (* find q and p *)
  148. B.Copy( dsa.p, test );
  149. test.Dec;
  150. r0 := B.Div( test, dsa.q ); (* r0 := (p-1)/q *)
  151. B.AssignInt( test, 2 );
  152. LOOP (* g := test ^ r0 mod p *)
  153. dsa.g := B.ModExp( test, r0, dsa.p );
  154. IF B.Cmp( dsa.g, one ) # 0 THEN EXIT END;
  155. test.Inc;
  156. END;
  157. END GenParams;
  158. PROCEDURE MakeKeys*( bits: INTEGER; CONST seed: ARRAY OF CHAR; VAR pub, priv: Key );
  159. BEGIN
  160. NEW( priv );
  161. GenParams( priv, bits, seed );
  162. REPEAT
  163. priv.y := B.NewRandRange( priv.q )
  164. UNTIL ~priv.y.IsZero( );
  165. NEW( pub ); pub^ := priv^;
  166. pub.y := B.ModExp( priv.g, priv.y, priv.p );
  167. priv.private := TRUE;
  168. priv.r := B.Mod( pub.y, priv.q ); (* r := (g ^ k mod p) mod q *)
  169. priv.inv := B.ModInverse( priv.y, priv.q ) (* part of 's := inv( k ) * (m + x*r) mod q' *)
  170. END MakeKeys;
  171. (** returns a new public key with exponent e and modulus m *)
  172. PROCEDURE PubKey*( p, q, g, y: Number ): Key;
  173. VAR dsa: Key;
  174. BEGIN
  175. NEW( dsa );
  176. dsa.name := "unkown";
  177. dsa.private := FALSE;
  178. B.Copy( p, dsa.p );
  179. B.Copy( q, dsa.q );
  180. B.Copy( g, dsa.g );
  181. B.Copy( y, dsa.y );
  182. RETURN dsa
  183. END PubKey;
  184. PROCEDURE LoadPrivateKey*( r: Streams.Reader; CONST passwd: ARRAY OF CHAR ): Key;
  185. (* TODO *)
  186. END LoadPrivateKey;
  187. PROCEDURE StorePrivateKey*( w: Streams.Writer; k: Key; CONST passwd: ARRAY OF CHAR );
  188. (* TODO *)
  189. END StorePrivateKey;
  190. PROCEDURE StorePublicKey*( w: Streams.Writer; k: Key ); (* openssh format *)
  191. VAR buf, encoded: ARRAY 4096 OF CHAR; pos: LONGINT;
  192. BEGIN
  193. ASSERT( ~k.private );
  194. w.String( "ssh-dss " );
  195. pos := 0;
  196. U.PutString( buf, pos, "ssh-dss" );
  197. U.PutBigNumber( buf, pos, k.p );
  198. U.PutBigNumber( buf, pos, k.q );
  199. U.PutBigNumber( buf, pos, k.g );
  200. U.PutBigNumber( buf, pos, k.y );
  201. Base64.Encode( buf, pos, encoded );
  202. w.String( encoded );
  203. w.String( " user@Aos" )
  204. END StorePublicKey;
  205. PROCEDURE LoadPublicKey*( r: Streams.Reader ): Key;
  206. VAR buf: ARRAY 4096 OF CHAR; len, pos: LONGINT;
  207. str: ARRAY 64 OF CHAR;
  208. k: Key;
  209. BEGIN
  210. NEW( k ); k.private := FALSE;
  211. len := Base64.DecodeStream( r, buf );
  212. pos := 0;
  213. U.GetString( buf, pos, str );
  214. ASSERT( str = "ssh-dss" );
  215. U.GetBigNumber( buf, pos, k.p );
  216. U.GetBigNumber( buf, pos, k.q );
  217. U.GetBigNumber( buf, pos, k.g );
  218. U.GetBigNumber( buf, pos, k.y );
  219. RETURN k
  220. END LoadPublicKey;
  221. BEGIN
  222. B.AssignInt( one, 1 );
  223. END CryptoDSA.
  224. System.Free CryptoDSA ~