123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- MODULE CryptoBase64; (** AUTHOR "g.f."; PURPOSE "Base 64 encoding according to RFC1421"; *)
- IMPORT Streams;
- VAR
- etab: ARRAY 64 OF CHAR;
- dtab: ARRAY 128 OF INTEGER;
- PROCEDURE Encode*( CONST image: ARRAY OF CHAR; len: LONGINT;
- VAR b64: ARRAY OF CHAR );
- VAR
- group, i, ix, ox: LONGINT;
- BEGIN
- group := 0; i := 0; ix := 0; ox := 0;
- WHILE ix < len DO
- group := group*100H + ORD( image[ix] ); INC( ix ); INC( i );
- IF i = 3 THEN
- b64[ox] := etab[group DIV 40000H MOD 64];
- b64[ox+1] := etab[group DIV 1000H MOD 64];
- b64[ox+2] := etab[group DIV 40H MOD 64];
- b64[ox+3] := etab[group MOD 64];
- INC( ox, 4 );
- group := 0;
- i := 0
- END;
- END;
- IF i > 0 THEN (*encode rest *)
- IF i = 1 THEN group := group*256 END;
- b64[ox] := etab[group DIV 400H MOD 64];
- b64[ox+1] := etab[group DIV 10H MOD 64];
- IF i = 1 THEN b64[ox+2] := '=' ELSE b64[ox+2] := etab[group*4 MOD 64] END;
- b64[ox+3] := '=';
- INC( ox, 4 );
- END;
- b64[ox] := 0X;
- END Encode;
- (* returns image length, negative value = error! *)
- PROCEDURE Decode*( CONST b64: ARRAY OF CHAR;
- VAR image: ARRAY OF CHAR ): LONGINT;
- VAR
- i, d, code, group, ix, len: LONGINT;
- c: CHAR;
- BEGIN
- len := 0; ix := 0; group := 0; i := 0;
- REPEAT c := b64[ix]; INC( ix ) UNTIL (c > ' ') OR (c = 0X);
- code := dtab[ORD( c )];
- WHILE code >= 0 DO
- group := group*64 + code; INC( i );
- IF i = 4 THEN
- image[len] := CHR( group DIV 10000H MOD 100H ); INC( len );
- image[len] := CHR( group DIV 100H MOD 100H ); INC( len );
- image[len] := CHR( group MOD 100H ); INC( len );
- group := 0; i := 0
- END;
- REPEAT c := b64[ix]; INC( ix ) UNTIL (c > ' ') OR (c = 0X);
- code := dtab[ORD( c )];
- END;
- IF c = '=' THEN (* decode rest *)
- IF i < 2 THEN (* error *) RETURN -1 END;
- group := group*64; d := 1; c := b64[ix];
- IF c = '=' THEN group := group*64; d := 2 END;
- image[len] := CHR( group DIV 10000H ); INC( len );
- IF d = 1 THEN image[len] := CHR( group DIV 100H MOD 100H ); INC( len ) END
- ELSIF i > 0 THEN (* error *) RETURN -1
- END;
- RETURN len
- END Decode;
- PROCEDURE EncodeStream*( CONST image: ARRAY OF CHAR; len: LONGINT;
- w: Streams.Writer );
- VAR
- group, i, ix, ll: LONGINT;
- BEGIN
- group := 0; i := 0; ix := 0; ll := 0;
- WHILE ix < len DO
- group := group*100H + ORD( image[ix] ); INC( ix ); INC( i );
- IF i = 3 THEN
- w.Char( etab[group DIV 40000H MOD 64] );
- w.Char( etab[group DIV 1000H MOD 64] );
- w.Char( etab[group DIV 40H MOD 64] );
- w.Char( etab[group MOD 64] );
- INC( ll, 4 );
- IF ll >= 72 THEN w.Ln; ll := 0 END;
- group := 0;
- i := 0
- END;
- END;
- IF i > 0 THEN (* encode rest *)
- IF i = 1 THEN group := group*100H END;
- w.Char( etab[group DIV 400H MOD 64] );
- w.Char( etab[group DIV 10H MOD 64] );
- IF i = 1 THEN w.Char( '=' ) ELSE w.Char( etab[group*4 MOD 64] ) END;
- w.Char( '=' );
- END;
- w.Update
- END EncodeStream;
- (* returns image length, negative value = error! *)
- PROCEDURE DecodeStream*( r: Streams.Reader;
- VAR image: ARRAY OF CHAR ): LONGINT;
- VAR
- i, rest, code, group, len: LONGINT;
- c: CHAR;
- BEGIN
- len := 0; group := 0; i := 0;
- REPEAT r.Char( c ) UNTIL (c > ' ') OR (c = 0X);
- code := dtab[ORD( c )];
- WHILE code >= 0 DO
- group := group*64 + code; INC( i );
- IF i = 4 THEN
- image[len] := CHR( group DIV 10000H MOD 100H ); INC( len );
- image[len] := CHR( group DIV 100H MOD 100H ); INC( len );
- image[len] := CHR( group MOD 100H ); INC( len );
- group := 0; i := 0
- END;
- REPEAT r.Char( c ) UNTIL (c > ' ') OR (c = 0X);
- code := dtab[ORD( c )];
- END;
- IF c = '=' THEN (* decode rest *)
- IF i < 2 THEN (* error *) RETURN -1 END;
- group := group*64; rest := 2; r.Char( c );
- IF c = '=' THEN group := group*64; rest := 1 END;
- image[len] := CHR( group DIV 10000H ); INC( len );
- IF rest = 2 THEN image[len] := CHR( group DIV 100H MOD 100H ); INC( len ) END
- ELSIF i > 0 THEN (* error *) RETURN -1
- END;
- RETURN len
- END DecodeStream;
- PROCEDURE InitTables;
- CONST
- letters = 26; digits = 10;
- VAR
- i, j: INTEGER;
- BEGIN
- j := 0;
- FOR i := 0 TO letters - 1 DO etab[j] := CHR( i + ORD("A") ); INC( j ) END;
- FOR i := 0 TO letters - 1 DO etab[j] := CHR( i + ORD("a") ); INC( j ) END;
- FOR i := 0 TO digits - 1 DO etab[j] := CHR( i + ORD("0") ); INC( j ) END;
- etab[62] := "+";
- etab[63] := "/";
- FOR i := 0 TO 127 DO dtab[i] := -1 END;
- FOR i := 0 TO 63 DO dtab[ORD( etab[i] )] := i END
- END InitTables;
- (*
- (* testing: expected behaviour: "admin:1234" => "YWRtaW46MTIzNA==" => "admin:1234"*)
- PROCEDURE Test*( c: Commands.Context );
- VAR image, base64: ARRAY 80 OF CHAR; len: LONGINT; r: Streams.StringReader;
- BEGIN
- c.out.String( 'admin:1234 => ' );
- image := 'admin:123456789';
- Encode( image, 10, base64 );
- c.out.String( base64 ); c.out.String( " => " );
- len := Decode( base64, image );
- IF len > 0 THEN
- image[len] := 0X;
- c.out.String(image); c.out.Ln;
- END;
- c.out.String( 'admin:1234 => ' );
- EncodeStream( 'admin:123456789', 10, c.out ); c.out.String( " => " );
- NEW( r, 80 ); r.Set( base64 );
- len := DecodeStream( r, image );
- IF len > 0 THEN
- image[len] := 0X;
- c.out.String( image ); c.out.Ln
- END
- END Test;
- *)
- BEGIN
- InitTables();
- END CryptoBase64.
- CryptoBase64.Test ~
- System.Free CryptoBase64 ~
|