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, Log := KernelLog;
  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: LONGINT; 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. B.Copy( e, rsa.exponent );
  127. B.Copy( m, rsa.modulus );
  128. RETURN rsa
  129. END PubKey;
  130. PROCEDURE ChineseRemainder( msg, d, p, q, u: Number ): Number;
  131. (*
  132. d: secret exponent
  133. p, q: prime factors of n
  134. u = (1/p) (mod q)
  135. Precondition: p < q
  136. *)
  137. VAR
  138. temp1, temp2, p2, q2: Number;
  139. BEGIN
  140. ASSERT( B.Cmp( p, q ) < 0, 100 );
  141. (* p2 := [(msg mod p) ^ (d mod (p-1))] mod p *)
  142. temp1 := B.Sub( p, one );
  143. temp2 := B.Mod( d, temp1 ); (* temp2 := d mod (p-1)) *)
  144. temp1 := B.Mod( msg, p ); (* temp1 := msg mod p *)
  145. p2 := B.ModExp( temp1, temp2, p );
  146. (* q2 := [(msg mod q) ^ (d mod (q-1))] mod q *)
  147. temp1 := B.Sub( q, one );
  148. temp2 := B.Mod( d, temp1 ); (* temp2 := d mod (q-1)) *)
  149. temp1 := B.Mod( msg, q ); (* temp1 := msg mod q *)
  150. q2 := B.ModExp( temp1, temp2, q );
  151. IF B.Cmp( q2, p2 ) = 0 THEN (* msg < p *)
  152. RETURN p2
  153. ELSE
  154. WHILE B.Cmp( q2, p2 ) < 0 DO q2 := B.Add( q2, q ) END;
  155. q2 := B.Sub( q2, p2 );
  156. temp1 := B.Mul( q2, u );
  157. temp2 := B.Mod( temp1, q );
  158. temp1 := B.Mul( p, temp2 );
  159. RETURN B.Add( temp1, p2 )
  160. END ;
  161. END ChineseRemainder;
  162. PROCEDURE LoadPrivateKey*( r: Streams.Reader; CONST passwd: ARRAY OF CHAR ): Key;
  163. VAR
  164. s: ARRAY 128 OF CHAR;
  165. c, l: Certificate;
  166. k: Key;
  167. cipher: Ciphers.Cipher;
  168. md5: MD5.Hash;
  169. digest: ARRAY 16 OF CHAR; pl: LONGINT;
  170. buf: ARRAY 4096 OF CHAR; bl, n, magic: LONGINT;
  171. BEGIN
  172. NEW( k );
  173. r.String( k.name );
  174. r.RawBool( k.private );
  175. ASSERT( k.private );
  176. r.RawLInt( k.size );
  177. r.RawLInt( k.time );
  178. r.RawLInt( k.date );
  179. r.RawLInt( bl );
  180. r.Bytes( buf, 0, bl, n );
  181. ASSERT( n = bl );
  182. pl := 0;
  183. WHILE passwd[pl] # 0X DO INC( pl ) END;
  184. NEW( md5 );
  185. md5.Initialize;
  186. md5.Update( passwd, 0, pl );
  187. md5.GetHash( digest, 0 );
  188. cipher := Ciphers.NewCipher("CryptoIDEA");
  189. cipher.InitKey( digest, 128 );
  190. cipher.Decrypt( buf, 0, bl );
  191. bl := 0;
  192. U.GetLength( buf, bl, magic );
  193. IF magic # PrivateKeyMagic THEN (* wrong passphrase*) RETURN NIL END;
  194. U.GetBigNumber( buf, bl, k.exponent );
  195. U.GetBigNumber( buf, bl, k.modulus );
  196. U.GetBigNumber( buf, bl, k.p );
  197. U.GetBigNumber( buf, bl, k.q );
  198. U.GetBigNumber( buf, bl, k.u );
  199. l := NIL;
  200. r.String( s );
  201. WHILE s # "EOC" DO
  202. NEW( c );
  203. COPY( s, c.authority );
  204. B.FileRead( r, c.signature );
  205. IF l = NIL THEN k.certificates := c ELSE l.next := c END;
  206. l := c;
  207. r.String( s )
  208. END;
  209. RETURN k
  210. END LoadPrivateKey;
  211. PROCEDURE StorePrivateKey*( w: Streams.Writer; k: Key; CONST passwd: ARRAY OF CHAR );
  212. VAR
  213. c: Certificate;
  214. cipher: Ciphers.Cipher;
  215. md5: MD5.Hash;
  216. digest: ARRAY 16 OF CHAR; pl: LONGINT;
  217. buf: ARRAY 4096 OF CHAR; bl: LONGINT;
  218. BEGIN
  219. ASSERT( k.private );
  220. w.Char( '"' ); w.String( k.name ); w.Char( '"' );
  221. w.RawBool( k.private );
  222. w.RawLInt( k.size );
  223. w.RawLInt( k.time );
  224. w.RawLInt( k.date );
  225. pl := 0;
  226. WHILE passwd[pl] # 0X DO INC( pl ) END;
  227. NEW( md5 );
  228. md5.Initialize;
  229. md5.Update( passwd, 0, pl );
  230. md5.GetHash( digest, 0 );
  231. cipher := Ciphers.NewCipher("CryptoIDEA");
  232. cipher.InitKey( digest, 128 );
  233. bl := 0;
  234. U.PutLength( buf, bl, PrivateKeyMagic );
  235. U.PutBigNumber( buf, bl, k.exponent );
  236. U.PutBigNumber( buf, bl, k.modulus );
  237. U.PutBigNumber( buf, bl, k.p );
  238. U.PutBigNumber( buf, bl, k.q );
  239. U.PutBigNumber( buf, bl, k.u );
  240. INC( bl, (-bl) MOD 16 );
  241. cipher.Encrypt( buf, 0, bl );
  242. w.RawLInt( bl );
  243. w.Bytes( buf, 0, bl );
  244. c := k.certificates;
  245. WHILE c # NIL DO
  246. w.String( c.authority );
  247. B.FileWrite( w, c.signature );
  248. c := c.next;
  249. END;
  250. w.String( "EOC" )
  251. END StorePrivateKey;
  252. PROCEDURE StorePublicKey*( w: Streams.Writer; k: Key ); (* openssh format *)
  253. VAR buf, encoded: ARRAY 4096 OF CHAR; pos: LONGINT;
  254. BEGIN
  255. ASSERT( ~k.private );
  256. w.String( "ssh-rsa " );
  257. pos := 0;
  258. U.PutString( buf, pos, "ssh-rsa" );
  259. U.PutBigNumber( buf, pos, k.exponent );
  260. U.PutBigNumber( buf, pos, k.modulus );
  261. Base64.Encode( buf, pos, encoded );
  262. w.String( encoded );
  263. w.String( " user@Aos" )
  264. END StorePublicKey;
  265. PROCEDURE LoadPublicKey*( r: Streams.Reader ): Key;
  266. VAR str: ARRAY 64 OF CHAR;
  267. BEGIN
  268. r.SkipWhitespace; r.String( str );
  269. ASSERT( str = "ssh-rsa" );
  270. RETURN ExtractPublicKey( r )
  271. END LoadPublicKey;
  272. PROCEDURE ExtractPublicKey*( r: Streams.Reader ): Key;
  273. VAR buf: ARRAY 4096 OF CHAR; len, pos: LONGINT;
  274. str: ARRAY 64 OF CHAR;
  275. k: Key;
  276. BEGIN
  277. NEW( k ); k.private := FALSE;
  278. len := Base64.DecodeStream( r, buf );
  279. Log.String( buf ); Log.Ln;
  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 ~