Back to... Zip-Ada

Source file : zip-crc_crypto.adb


package body Zip.CRC_Crypto is

  CRC32_Table : array( Unsigned_32'(0)..255 ) of Unsigned_32;

  procedure Prepare_table is
    -- CRC-32 algorithm, ISO-3309
    Seed: constant:= 16#EDB88320#;
    l: Unsigned_32;
  begin
    for i in CRC32_Table'Range loop
      l:= i;
      for bit in 0..7 loop
        if (l and 1) = 0 then
          l:= Shift_Right(l,1);
        else
          l:= Shift_Right(l,1) xor Seed;
        end if;
      end loop;
      CRC32_Table(i):= l;
    end loop;
  end Prepare_table;

  procedure Update( CRC: in out Unsigned_32; InBuf: Zip.Byte_Buffer ) is
    local_CRC: Unsigned_32;
  begin
    local_CRC:= CRC ;
    for i in InBuf'Range loop
      local_CRC :=
        CRC32_Table( 16#FF# and ( local_CRC xor Unsigned_32( InBuf(i) ) ) )
        xor
        Shift_Right( local_CRC , 8 );
    end loop;
    CRC:= local_CRC;
  end Update;

  table_empty: Boolean:= True;

  procedure Init( CRC: out Unsigned_32 ) is
  begin
    if table_empty then
      Prepare_table;
      table_empty:= False;
    end if;
    CRC:= 16#FFFF_FFFF#;
  end Init;

  function Final( CRC: Unsigned_32 ) return Unsigned_32 is
  begin
    return not CRC;
  end Final;

  --

  procedure Set_mode(obj: in out Crypto_pack; new_mode: Crypto_Mode) is
  begin
    obj.current_mode:= new_mode;
  end Set_mode;

  function Get_mode(obj: Crypto_pack) return Crypto_Mode is
  begin
    return obj.current_mode;
  end Get_mode;

  procedure Update_keys(obj: in out Crypto_pack; by: Zip.Byte ) is
  begin
    Update( obj.keys(0), (0 => by) );
    obj.keys(1) := obj.keys(1) + (obj.keys(0) and 16#000000ff#);
    obj.keys(1) := obj.keys(1) * 134775813 + 1;
    Update(
      obj.keys(2),
      (0 => Zip.Byte(Shift_Right( obj.keys(1), 24 )))
    );
  end Update_keys;

  --  Crypto_code: Pseudo-random byte to be XOR'ed with.
  function Crypto_code(obj: Crypto_pack) return Zip.Byte is
  pragma Inline(Crypto_code);
    temp: Unsigned_16;
  begin
    temp:= Unsigned_16(obj.keys(2) and 16#ffff#) or 2;
    return Zip.Byte(Shift_Right(temp * (temp xor 1), 8));
  end Crypto_code;

  procedure Init_keys(obj: in out Crypto_pack; password: String) is
  begin
    obj.keys:= ( 16#12345678#, 16#23456789#, 16#34567890# );
    for i in password'Range loop
      Update_keys(obj, Character'Pos(password(i)));
    end loop;
  end Init_keys;

  procedure Encode(obj: in out Crypto_pack; buf: in out Zip.Byte_Buffer) is
    bc: Zip.Byte;
  begin
    if obj.current_mode = encrypted then
      for i in buf'Range loop
        bc:= buf(i);
        buf(i):= bc xor Crypto_code(obj);
        Update_keys(obj, bc);  -- Keys are updated with the unencrypted byte
      end loop;
    end if;
  end Encode;

  procedure Decode(obj: in out Crypto_pack; b: in out Unsigned_8) is
  begin
    if obj.current_mode = encrypted then
      b:= b xor Crypto_code(obj);
      Update_keys(obj, b);     -- Keys are updated with the unencrypted byte
    end if;
  end Decode;

end Zip.CRC_Crypto;

Zip-Ada: Ada library for zip archive files (.zip). Ada programming.
Some news about Zip-Ada and other related Ada projects on Gautier's blog.