blob: 20a53a78a5d36c890ecc171d4d757c22d357ea8f [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT LIBRARY COMPONENTS --
-- --
-- G N A T . S E C U R E _ H A S H E S . S H A 1 --
-- --
-- B o d y --
-- --
-- Copyright (C) 2002-2022, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. --
-- --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception, --
-- version 3.1, as published by the Free Software Foundation. --
-- --
-- You should have received a copy of the GNU General Public License and --
-- a copy of the GCC Runtime Library Exception along with this program; --
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
-- <http://www.gnu.org/licenses/>. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
package body GNAT.Secure_Hashes.SHA1 is
use Interfaces;
use GNAT.Byte_Swapping;
-- The following functions are the four elementary components of each
-- of the four round groups (0 .. 19, 20 .. 39, 40 .. 59, and 60 .. 79)
-- defined in RFC 3174.
function F0 (B, C, D : Unsigned_32) return Unsigned_32;
pragma Inline (F0);
function F1 (B, C, D : Unsigned_32) return Unsigned_32;
pragma Inline (F1);
function F2 (B, C, D : Unsigned_32) return Unsigned_32;
pragma Inline (F2);
function F3 (B, C, D : Unsigned_32) return Unsigned_32;
pragma Inline (F3);
--------
-- F0 --
--------
function F0
(B, C, D : Interfaces.Unsigned_32) return Interfaces.Unsigned_32
is
begin
return (B and C) or ((not B) and D);
end F0;
--------
-- F1 --
--------
function F1
(B, C, D : Interfaces.Unsigned_32) return Interfaces.Unsigned_32
is
begin
return B xor C xor D;
end F1;
--------
-- F2 --
--------
function F2
(B, C, D : Interfaces.Unsigned_32) return Interfaces.Unsigned_32
is
begin
return (B and C) or (B and D) or (C and D);
end F2;
--------
-- F3 --
--------
function F3
(B, C, D : Interfaces.Unsigned_32) return Interfaces.Unsigned_32
renames F1;
---------------
-- Transform --
---------------
procedure Transform
(H : in out Hash_State.State;
M : in out Message_State)
is
use System;
type Words is array (Natural range <>) of Interfaces.Unsigned_32;
X : Words (0 .. 15);
for X'Address use M.Buffer'Address;
pragma Import (Ada, X);
W : Words (0 .. 79);
A, B, C, D, E, Temp : Interfaces.Unsigned_32;
begin
if Default_Bit_Order /= High_Order_First then
for J in X'Range loop
Swap4 (X (J)'Address);
end loop;
end if;
-- a. Divide data block into sixteen words
W (0 .. 15) := X;
-- b. Prepare working block of 80 words
for T in 16 .. 79 loop
-- W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16))
W (T) := Rotate_Left
(W (T - 3) xor W (T - 8) xor W (T - 14) xor W (T - 16), 1);
end loop;
-- c. Set up transformation variables
A := H (0);
B := H (1);
C := H (2);
D := H (3);
E := H (4);
-- d. For each of the 80 rounds, compute:
-- TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t);
-- E = D; D = C; C = S^30(B); B = A; A = TEMP;
for T in 0 .. 19 loop
Temp := Rotate_Left (A, 5) + F0 (B, C, D) + E + W (T) + 16#5A827999#;
E := D; D := C; C := Rotate_Left (B, 30); B := A; A := Temp;
end loop;
for T in 20 .. 39 loop
Temp := Rotate_Left (A, 5) + F1 (B, C, D) + E + W (T) + 16#6ED9EBA1#;
E := D; D := C; C := Rotate_Left (B, 30); B := A; A := Temp;
end loop;
for T in 40 .. 59 loop
Temp := Rotate_Left (A, 5) + F2 (B, C, D) + E + W (T) + 16#8F1BBCDC#;
E := D; D := C; C := Rotate_Left (B, 30); B := A; A := Temp;
end loop;
for T in 60 .. 79 loop
Temp := Rotate_Left (A, 5) + F3 (B, C, D) + E + W (T) + 16#CA62C1D6#;
E := D; D := C; C := Rotate_Left (B, 30); B := A; A := Temp;
end loop;
-- e. Update context:
-- H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E
H (0) := H (0) + A;
H (1) := H (1) + B;
H (2) := H (2) + C;
H (3) := H (3) + D;
H (4) := H (4) + E;
end Transform;
end GNAT.Secure_Hashes.SHA1;