CryptoRSA.Mod 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. MODULE CryptoRSA; (** AUTHOR "G.F."; PURPOSE "RSA"; *)
  2. (* Excerpt of Crypt.Mod jm 23.8.95.*)
  3. IMPORT
  4. B := CryptoBigNumbers, U := CryptoUtils, MD5 := CryptoMD5, Ciphers := CryptoCiphers,
  5. Base64 := CryptoBase64, Streams, Clock;
  6. CONST
  7. chinese = TRUE;
  8. PrivateKeyMagic = 3F6FF9EBH;
  9. TYPE
  10. Number = B.BigNumber;
  11. Buffer = ARRAY 16 OF CHAR;
  12. Certificate* = OBJECT
  13. VAR
  14. authority*: ARRAY 128 OF CHAR; (** Certifying authority. *)
  15. signature*: Number; (** Signature of key. *)
  16. next*: Certificate
  17. END Certificate;
  18. Key* = OBJECT
  19. VAR
  20. name-: ARRAY 128 OF CHAR; (** Owner of this key. *)
  21. private-: BOOLEAN; (** Is this a private key? then the exponent is encrypted *)
  22. size-: LONGINT;
  23. exponent-, modulus-: Number;
  24. p, q, u: Number; (* for chinese remainder theorem *)
  25. time-, date-: LONGINT;
  26. certificates*: Certificate;
  27. next*: Key;
  28. PROCEDURE Sign*( CONST digest: ARRAY OF CHAR; dlen: LONGINT ): Number;
  29. VAR msg: Number;
  30. BEGIN
  31. ASSERT( private );
  32. B.AssignBin( msg, digest, 0, dlen );
  33. IF chinese THEN (* Using chinese remainder: *)
  34. RETURN ChineseRemainder( msg, exponent, p, q, u )
  35. ELSE
  36. RETURN B.ModExp( msg, exponent, modulus );
  37. END;
  38. END Sign;
  39. PROCEDURE Verify*( CONST digest: ARRAY OF CHAR; dlen: LONGINT; signature: Number ): BOOLEAN;
  40. VAR
  41. msg: Number;
  42. i, l: LONGINT;
  43. buf: Buffer;
  44. BEGIN
  45. ASSERT( ~private & (dlen >= 16) );
  46. msg := B.ModExp( signature, exponent, modulus );
  47. l := msg.len;
  48. FOR i := 0 TO 3 DO l2n( msg.d[l - 1 - i], buf, 4*i ) END;
  49. FOR i := 0 TO 15 DO
  50. IF buf[i] # digest[i] THEN RETURN FALSE END;
  51. END;
  52. RETURN TRUE
  53. END Verify;
  54. PROCEDURE Encrypt*( msg: Number ): Number;
  55. BEGIN
  56. ASSERT( ~private );
  57. RETURN B.ModExp( msg, exponent, modulus );
  58. END Encrypt;
  59. PROCEDURE Decrypt*( msg: Number ): Number;
  60. BEGIN
  61. ASSERT( private );
  62. IF chinese THEN (* Using chinese remainder: *)
  63. RETURN ChineseRemainder( msg, exponent, p, q, u )
  64. ELSE
  65. RETURN B.ModExp( msg, exponent, modulus );
  66. END;
  67. END Decrypt;
  68. END Key;
  69. VAR
  70. one, two: Number; (* constants *)
  71. (* converts LONGINT to ARRAY OF CHAR; big endian order *)
  72. PROCEDURE l2n( l: UNSIGNED32; VAR buf: Buffer; pos: LONGINT );
  73. VAR i: LONGINT;
  74. BEGIN
  75. i := pos + 3;
  76. WHILE i >= pos DO
  77. buf[i] := CHR( l MOD 256 );
  78. l := l DIV 256;
  79. DEC( i )
  80. END
  81. END l2n;
  82. (** Generate public and private keys out of the large primes p and q, using the specified public exponent e.
  83. The private key's exponent will be enrypted with IDEA and key passwd *)
  84. PROCEDURE MakeKeys*( p, q, e: Number; CONST name: ARRAY OF CHAR; VAR pub, priv: Key );
  85. VAR
  86. n, p1, q1, x, d: Number;
  87. BEGIN
  88. ASSERT( B.Cmp( p, q ) # 0 );
  89. n := B.Mul( p, q );
  90. B.Copy( p, p1 ); p1.Dec;
  91. B.Copy( q, q1 ); q1.Dec;
  92. x := B.Mul( p1, q1 );
  93. d := B.ModInverse( e, x );
  94. NEW( pub);
  95. pub.modulus := n;
  96. pub.exponent := e;
  97. pub.size := n.len*32;
  98. pub.private := FALSE;
  99. NEW( priv );
  100. priv.modulus := n;
  101. priv.exponent := d;
  102. priv.size := n.len*32;
  103. priv.private := TRUE;
  104. (* Add stuff needed for the chinese remainder theorem to the private key *)
  105. IF B.Cmp( p, q ) < 0 THEN (* p < q *)
  106. B.Copy( p, priv.p );
  107. B.Copy( q, priv.q );
  108. ELSE
  109. B.Copy( q, priv.p );
  110. B.Copy( p, priv.q );
  111. END;
  112. priv.u := B.ModInverse( priv.p, priv.q );
  113. Clock.Get( pub.time, pub.date );
  114. priv.time := pub.time;
  115. priv.date := pub.date;
  116. COPY( name, pub.name );
  117. COPY( name, priv.name );
  118. END MakeKeys;
  119. (** returns a new public key with exponent e and modulus m *)
  120. PROCEDURE PubKey*( e, m: Number ): Key;
  121. VAR rsa: Key;
  122. BEGIN
  123. NEW( rsa );
  124. rsa.name := "unkown";
  125. rsa.private := FALSE;
  126. rsa.size := m.len*32;
  127. B.Copy( e, rsa.exponent );
  128. B.Copy( m, rsa.modulus );
  129. RETURN rsa
  130. END PubKey;
  131. PROCEDURE ChineseRemainder( msg, d, p, q, u: Number ): Number;
  132. (*
  133. d: secret exponent
  134. p, q: prime factors of n
  135. u = (1/p) (mod q)
  136. Precondition: p < q
  137. *)
  138. VAR
  139. temp1, temp2, p2, q2: Number;
  140. BEGIN
  141. ASSERT( B.Cmp( p, q ) < 0, 100 );
  142. (* p2 := [(msg mod p) ^ (d mod (p-1))] mod p *)
  143. temp1 := B.Sub( p, one );
  144. temp2 := B.Mod( d, temp1 ); (* temp2 := d mod (p-1)) *)
  145. temp1 := B.Mod( msg, p ); (* temp1 := msg mod p *)
  146. p2 := B.ModExp( temp1, temp2, p );
  147. (* q2 := [(msg mod q) ^ (d mod (q-1))] mod q *)
  148. temp1 := B.Sub( q, one );
  149. temp2 := B.Mod( d, temp1 ); (* temp2 := d mod (q-1)) *)
  150. temp1 := B.Mod( msg, q ); (* temp1 := msg mod q *)
  151. q2 := B.ModExp( temp1, temp2, q );
  152. IF B.Cmp( q2, p2 ) = 0 THEN (* msg < p *)
  153. RETURN p2
  154. ELSE
  155. WHILE B.Cmp( q2, p2 ) < 0 DO q2 := B.Add( q2, q ) END;
  156. q2 := B.Sub( q2, p2 );
  157. temp1 := B.Mul( q2, u );
  158. temp2 := B.Mod( temp1, q );
  159. temp1 := B.Mul( p, temp2 );
  160. RETURN B.Add( temp1, p2 )
  161. END ;
  162. END ChineseRemainder;
  163. PROCEDURE LoadPrivateKey*( r: Streams.Reader; CONST passwd: ARRAY OF CHAR ): Key;
  164. VAR
  165. s: ARRAY 128 OF CHAR;
  166. c, l: Certificate;
  167. k: Key;
  168. cipher: Ciphers.Cipher;
  169. md5: MD5.Hash;
  170. digest: ARRAY 16 OF CHAR; pl: LONGINT;
  171. buf: ARRAY 4096 OF CHAR; bl, n, magic: LONGINT;
  172. BEGIN
  173. NEW( k );
  174. r.String( k.name );
  175. r.RawBool( k.private );
  176. ASSERT( k.private );
  177. r.RawLInt( k.size );
  178. r.RawLInt( k.time );
  179. r.RawLInt( k.date );
  180. r.RawLInt( bl );
  181. r.Bytes( buf, 0, bl, n );
  182. ASSERT( n = bl );
  183. pl := 0;
  184. WHILE passwd[pl] # 0X DO INC( pl ) END;
  185. NEW( md5 );
  186. md5.Initialize;
  187. md5.Update( passwd, 0, pl );
  188. md5.GetHash( digest, 0 );
  189. cipher := Ciphers.NewCipher("CryptoIDEA");
  190. cipher.InitKey( digest, 128 );
  191. cipher.Decrypt( buf, 0, bl );
  192. bl := 0;
  193. U.GetLength( buf, bl, magic );
  194. IF magic # PrivateKeyMagic THEN (* wrong passphrase*) RETURN NIL END;
  195. U.GetBigNumber( buf, bl, k.exponent );
  196. U.GetBigNumber( buf, bl, k.modulus );
  197. U.GetBigNumber( buf, bl, k.p );
  198. U.GetBigNumber( buf, bl, k.q );
  199. U.GetBigNumber( buf, bl, k.u );
  200. l := NIL;
  201. r.String( s );
  202. WHILE s # "EOC" DO
  203. NEW( c );
  204. COPY( s, c.authority );
  205. B.FileRead( r, c.signature );
  206. IF l = NIL THEN k.certificates := c ELSE l.next := c END;
  207. l := c;
  208. r.String( s )
  209. END;
  210. RETURN k
  211. END LoadPrivateKey;
  212. PROCEDURE StorePrivateKey*( w: Streams.Writer; k: Key; CONST passwd: ARRAY OF CHAR );
  213. VAR
  214. c: Certificate;
  215. cipher: Ciphers.Cipher;
  216. md5: MD5.Hash;
  217. digest: ARRAY 16 OF CHAR; pl: LONGINT;
  218. buf: ARRAY 4096 OF CHAR; bl: LONGINT;
  219. BEGIN
  220. ASSERT( k.private );
  221. w.Char( '"' ); w.String( k.name ); w.Char( '"' );
  222. w.RawBool( k.private );
  223. w.RawLInt( k.size );
  224. w.RawLInt( k.time );
  225. w.RawLInt( k.date );
  226. pl := 0;
  227. WHILE passwd[pl] # 0X DO INC( pl ) END;
  228. NEW( md5 );
  229. md5.Initialize;
  230. md5.Update( passwd, 0, pl );
  231. md5.GetHash( digest, 0 );
  232. cipher := Ciphers.NewCipher("CryptoIDEA");
  233. cipher.InitKey( digest, 128 );
  234. bl := 0;
  235. U.PutLength( buf, bl, PrivateKeyMagic );
  236. U.PutBigNumber( buf, bl, k.exponent );
  237. U.PutBigNumber( buf, bl, k.modulus );
  238. U.PutBigNumber( buf, bl, k.p );
  239. U.PutBigNumber( buf, bl, k.q );
  240. U.PutBigNumber( buf, bl, k.u );
  241. INC( bl, (-bl) MOD 16 );
  242. cipher.Encrypt( buf, 0, bl );
  243. w.RawLInt( bl );
  244. w.Bytes( buf, 0, bl );
  245. c := k.certificates;
  246. WHILE c # NIL DO
  247. w.String( c.authority );
  248. B.FileWrite( w, c.signature );
  249. c := c.next;
  250. END;
  251. w.String( "EOC" )
  252. END StorePrivateKey;
  253. PROCEDURE StorePublicKey*( w: Streams.Writer; k: Key ); (* openssh format *)
  254. VAR buf, encoded: ARRAY 4096 OF CHAR; pos: LONGINT;
  255. BEGIN
  256. ASSERT( ~k.private );
  257. w.String( "ssh-rsa " );
  258. pos := 0;
  259. U.PutString( buf, pos, "ssh-rsa" );
  260. U.PutBigNumber( buf, pos, k.exponent );
  261. U.PutBigNumber( buf, pos, k.modulus );
  262. Base64.Encode( buf, pos, encoded );
  263. w.String( encoded );
  264. w.String( " user@Aos" )
  265. END StorePublicKey;
  266. PROCEDURE LoadPublicKey*( r: Streams.Reader ): Key;
  267. VAR str: ARRAY 64 OF CHAR;
  268. BEGIN
  269. r.SkipWhitespace; r.String( str );
  270. ASSERT( str = "ssh-rsa" );
  271. RETURN ExtractPublicKey( r )
  272. END LoadPublicKey;
  273. PROCEDURE ExtractPublicKey*( r: Streams.Reader ): Key;
  274. VAR buf: ARRAY 4096 OF CHAR; len, pos: LONGINT;
  275. str: ARRAY 64 OF CHAR;
  276. k: Key;
  277. BEGIN
  278. NEW( k ); k.private := FALSE;
  279. len := Base64.DecodeStream( r, buf );
  280. pos := 0;
  281. U.GetString( buf, pos, str );
  282. ASSERT( str = "ssh-rsa" );
  283. U.GetBigNumber( buf, pos, k.exponent );
  284. U.GetBigNumber( buf, pos, k.modulus );
  285. RETURN k
  286. END ExtractPublicKey;
  287. BEGIN
  288. B.AssignInt( one, 1 );
  289. B.AssignInt( two, 2 );
  290. END CryptoRSA.
  291. System.Free CryptoRSA ~