CryptoBase64.Mod 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. MODULE CryptoBase64; (** AUTHOR "g.f."; PURPOSE "Base 64 encoding according to RFC1421"; *)
  2. IMPORT Streams;
  3. VAR
  4. etab: ARRAY 64 OF CHAR;
  5. dtab: ARRAY 128 OF INTEGER;
  6. PROCEDURE Encode*( CONST image: ARRAY OF CHAR; len: LONGINT;
  7. VAR b64: ARRAY OF CHAR );
  8. VAR
  9. group, i, ix, ox: LONGINT;
  10. BEGIN
  11. group := 0; i := 0; ix := 0; ox := 0;
  12. WHILE ix < len DO
  13. group := group*100H + ORD( image[ix] ); INC( ix ); INC( i );
  14. IF i = 3 THEN
  15. b64[ox] := etab[group DIV 40000H MOD 64];
  16. b64[ox+1] := etab[group DIV 1000H MOD 64];
  17. b64[ox+2] := etab[group DIV 40H MOD 64];
  18. b64[ox+3] := etab[group MOD 64];
  19. INC( ox, 4 );
  20. group := 0;
  21. i := 0
  22. END;
  23. END;
  24. IF i > 0 THEN (*encode rest *)
  25. IF i = 1 THEN group := group*256 END;
  26. b64[ox] := etab[group DIV 400H MOD 64];
  27. b64[ox+1] := etab[group DIV 10H MOD 64];
  28. IF i = 1 THEN b64[ox+2] := '=' ELSE b64[ox+2] := etab[group*4 MOD 64] END;
  29. b64[ox+3] := '=';
  30. INC( ox, 4 );
  31. END;
  32. b64[ox] := 0X;
  33. END Encode;
  34. (* returns image length, negative value = error! *)
  35. PROCEDURE Decode*( CONST b64: ARRAY OF CHAR;
  36. VAR image: ARRAY OF CHAR ): LONGINT;
  37. VAR
  38. i, d, code, group, ix, len: LONGINT;
  39. c: CHAR;
  40. BEGIN
  41. len := 0; ix := 0; group := 0; i := 0;
  42. REPEAT c := b64[ix]; INC( ix ) UNTIL (c > ' ') OR (c = 0X);
  43. code := dtab[ORD( c )];
  44. WHILE code >= 0 DO
  45. group := group*64 + code; INC( i );
  46. IF i = 4 THEN
  47. image[len] := CHR( group DIV 10000H MOD 100H ); INC( len );
  48. image[len] := CHR( group DIV 100H MOD 100H ); INC( len );
  49. image[len] := CHR( group MOD 100H ); INC( len );
  50. group := 0; i := 0
  51. END;
  52. REPEAT c := b64[ix]; INC( ix ) UNTIL (c > ' ') OR (c = 0X);
  53. code := dtab[ORD( c )];
  54. END;
  55. IF c = '=' THEN (* decode rest *)
  56. IF i < 2 THEN (* error *) RETURN -1 END;
  57. group := group*64; d := 1; c := b64[ix];
  58. IF c = '=' THEN group := group*64; d := 2 END;
  59. image[len] := CHR( group DIV 10000H ); INC( len );
  60. IF d = 1 THEN image[len] := CHR( group DIV 100H MOD 100H ); INC( len ) END
  61. ELSIF i > 0 THEN (* error *) RETURN -1
  62. END;
  63. RETURN len
  64. END Decode;
  65. PROCEDURE EncodeStream*( CONST image: ARRAY OF CHAR; len: LONGINT;
  66. w: Streams.Writer );
  67. VAR
  68. group, i, ix, ll: LONGINT;
  69. BEGIN
  70. group := 0; i := 0; ix := 0; ll := 0;
  71. WHILE ix < len DO
  72. group := group*100H + ORD( image[ix] ); INC( ix ); INC( i );
  73. IF i = 3 THEN
  74. w.Char( etab[group DIV 40000H MOD 64] );
  75. w.Char( etab[group DIV 1000H MOD 64] );
  76. w.Char( etab[group DIV 40H MOD 64] );
  77. w.Char( etab[group MOD 64] );
  78. INC( ll, 4 );
  79. IF ll >= 72 THEN w.Ln; ll := 0 END;
  80. group := 0;
  81. i := 0
  82. END;
  83. END;
  84. IF i > 0 THEN (* encode rest *)
  85. IF i = 1 THEN group := group*100H END;
  86. w.Char( etab[group DIV 400H MOD 64] );
  87. w.Char( etab[group DIV 10H MOD 64] );
  88. IF i = 1 THEN w.Char( '=' ) ELSE w.Char( etab[group*4 MOD 64] ) END;
  89. w.Char( '=' );
  90. END;
  91. w.Update
  92. END EncodeStream;
  93. (* returns image length, negative value = error! *)
  94. PROCEDURE DecodeStream*( r: Streams.Reader;
  95. VAR image: ARRAY OF CHAR ): LONGINT;
  96. VAR
  97. i, rest, code, group, len: LONGINT;
  98. c: CHAR;
  99. BEGIN
  100. len := 0; group := 0; i := 0;
  101. REPEAT r.Char( c ) UNTIL (c > ' ') OR (c = 0X);
  102. code := dtab[ORD( c )];
  103. WHILE code >= 0 DO
  104. group := group*64 + code; INC( i );
  105. IF i = 4 THEN
  106. image[len] := CHR( group DIV 10000H MOD 100H ); INC( len );
  107. image[len] := CHR( group DIV 100H MOD 100H ); INC( len );
  108. image[len] := CHR( group MOD 100H ); INC( len );
  109. group := 0; i := 0
  110. END;
  111. REPEAT r.Char( c ) UNTIL (c > ' ') OR (c = 0X);
  112. code := dtab[ORD( c )];
  113. END;
  114. IF c = '=' THEN (* decode rest *)
  115. IF i < 2 THEN (* error *) RETURN -1 END;
  116. group := group*64; rest := 2; r.Char( c );
  117. IF c = '=' THEN group := group*64; rest := 1 END;
  118. image[len] := CHR( group DIV 10000H ); INC( len );
  119. IF rest = 2 THEN image[len] := CHR( group DIV 100H MOD 100H ); INC( len ) END
  120. ELSIF i > 0 THEN (* error *) RETURN -1
  121. END;
  122. RETURN len
  123. END DecodeStream;
  124. PROCEDURE InitTables;
  125. CONST
  126. letters = 26; digits = 10;
  127. VAR
  128. i, j: INTEGER;
  129. BEGIN
  130. j := 0;
  131. FOR i := 0 TO letters - 1 DO etab[j] := CHR( i + ORD("A") ); INC( j ) END;
  132. FOR i := 0 TO letters - 1 DO etab[j] := CHR( i + ORD("a") ); INC( j ) END;
  133. FOR i := 0 TO digits - 1 DO etab[j] := CHR( i + ORD("0") ); INC( j ) END;
  134. etab[62] := "+";
  135. etab[63] := "/";
  136. FOR i := 0 TO 127 DO dtab[i] := -1 END;
  137. FOR i := 0 TO 63 DO dtab[ORD( etab[i] )] := i END
  138. END InitTables;
  139. (*
  140. (* testing: expected behaviour: "admin:1234" => "YWRtaW46MTIzNA==" => "admin:1234"*)
  141. PROCEDURE Test*( c: Commands.Context );
  142. VAR image, base64: ARRAY 80 OF CHAR; len: LONGINT; r: Streams.StringReader;
  143. BEGIN
  144. c.out.String( 'admin:1234 => ' );
  145. image := 'admin:123456789';
  146. Encode( image, 10, base64 );
  147. c.out.String( base64 ); c.out.String( " => " );
  148. len := Decode( base64, image );
  149. IF len > 0 THEN
  150. image[len] := 0X;
  151. c.out.String(image); c.out.Ln;
  152. END;
  153. c.out.String( 'admin:1234 => ' );
  154. EncodeStream( 'admin:123456789', 10, c.out ); c.out.String( " => " );
  155. NEW( r, 80 ); r.Set( base64 );
  156. len := DecodeStream( r, image );
  157. IF len > 0 THEN
  158. image[len] := 0X;
  159. c.out.String( image ); c.out.Ln
  160. END
  161. END Test;
  162. *)
  163. BEGIN
  164. InitTables();
  165. END CryptoBase64.
  166. CryptoBase64.Test ~
  167. System.Free CryptoBase64 ~