1 % Copyright (C) 2001, 2004 Ian Lynagh <igloo@earth.li>
3 % This program is free software; you can redistribute it and/or modify
4 % it under the terms of the GNU General Public License as published by
5 % the Free Software Foundation; either version 2, or (at your option)
8 % This program is distributed in the hope that it will be useful,
9 % but WITHOUT ANY WARRANTY; without even the implied warranty of
10 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 % GNU General Public License for more details.
13 % You should have received a copy of the GNU General Public License
14 % along with this program; see the file COPYING. If not, write to
15 % the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 % Boston, MA 02110-1301, USA.
19 {-# OPTIONS_GHC -fglasgow-exts -fno-warn-name-shadowing #-}
20 -- -fglasgow-exts needed for nasty hack below
21 -- name shadowing disabled because a,b,c,d,e are shadowed loads in step 4
22 module SHA1 (sha1PS) where
24 import Autoconf (big_endian)
25 import FastPackedString (PackedString, unsafeWithInternals,
26 concatPS, packWords, lengthPS)
28 import Control.Monad (unless)
29 import Data.Char (intToDigit)
30 import Data.Bits (xor, (.&.), (.|.), complement, rotateL, shiftL, shiftR)
31 import Data.Word (Word8, Word32)
32 import Foreign.Ptr (Ptr, castPtr)
33 import Foreign.Marshal.Array (advancePtr)
34 import Foreign.Storable (peek, poke)
35 import System.IO.Unsafe (unsafePerformIO)
37 data ABCDE = ABCDE !Word32 !Word32 !Word32 !Word32 !Word32
38 data XYZ = XYZ !Word32 !Word32 !Word32
40 sha1PS :: PackedString -> String
42 where s1_2 = sha1_step_1_2_pad_length s
43 abcde = sha1_step_3_init
44 abcde' = unsafePerformIO
45 $ unsafeWithInternals s1_2 (\ptr len ->
46 do let ptr' = castPtr ptr
47 unless big_endian $ fiddle_endianness ptr' len
48 sha1_step_4_main abcde ptr' len)
49 s5 = sha1_step_5_display abcde'
51 fiddle_endianness :: Ptr Word32 -> Int -> IO ()
52 fiddle_endianness p 0 = p `seq` return ()
56 .|. shiftL (x .&. 0xff00) 8
57 .|. (shiftR x 8 .&. 0xff00)
59 fiddle_endianness (p `advancePtr` 1) (n - 4)
62 sha1_step_1_2_pad_length assumes the length is at most 2^61.
63 This seems reasonable as the Int used to represent it is normally 32bit,
64 but obviously could go wrong with large inputs on 64bit machines.
65 The PackedString library should probably move to Word64s if this is an
69 sha1_step_1_2_pad_length :: PackedString -> PackedString
70 sha1_step_1_2_pad_length s
71 = let len = lengthPS s
72 num_nuls = (55 - len) `mod` 64
73 padding = 128:replicate num_nuls 0
74 len_w8s = reverse $ size_split 8 (fromIntegral len*8)
75 in concatPS [s, packWords padding, packWords len_w8s]
77 size_split :: Int -> Integer -> [Word8]
79 size_split p n = fromIntegral d:size_split (p-1) n'
80 where (n', d) = divMod n 256
82 sha1_step_3_init :: ABCDE
83 sha1_step_3_init = ABCDE 0x67452301 0xefcdab89 0x98badcfe 0x10325476 0xc3d2e1f0
87 sha1_step_4_main :: ABCDE -> Ptr Word32 -> Int -> IO ABCDE
88 sha1_step_4_main abcde _ 0 = return $! abcde
89 sha1_step_4_main (ABCDE a0@a b0@b c0@c d0@d e0@e) s len
91 (e, b) <- doit f1 0x5a827999 (x 0) a b c d e
92 (d, a) <- doit f1 0x5a827999 (x 1) e a b c d
93 (c, e) <- doit f1 0x5a827999 (x 2) d e a b c
94 (b, d) <- doit f1 0x5a827999 (x 3) c d e a b
95 (a, c) <- doit f1 0x5a827999 (x 4) b c d e a
96 (e, b) <- doit f1 0x5a827999 (x 5) a b c d e
97 (d, a) <- doit f1 0x5a827999 (x 6) e a b c d
98 (c, e) <- doit f1 0x5a827999 (x 7) d e a b c
99 (b, d) <- doit f1 0x5a827999 (x 8) c d e a b
100 (a, c) <- doit f1 0x5a827999 (x 9) b c d e a
101 (e, b) <- doit f1 0x5a827999 (x 10) a b c d e
102 (d, a) <- doit f1 0x5a827999 (x 11) e a b c d
103 (c, e) <- doit f1 0x5a827999 (x 12) d e a b c
104 (b, d) <- doit f1 0x5a827999 (x 13) c d e a b
105 (a, c) <- doit f1 0x5a827999 (x 14) b c d e a
106 (e, b) <- doit f1 0x5a827999 (x 15) a b c d e
107 (d, a) <- doit f1 0x5a827999 (m 16) e a b c d
108 (c, e) <- doit f1 0x5a827999 (m 17) d e a b c
109 (b, d) <- doit f1 0x5a827999 (m 18) c d e a b
110 (a, c) <- doit f1 0x5a827999 (m 19) b c d e a
111 (e, b) <- doit f2 0x6ed9eba1 (m 20) a b c d e
112 (d, a) <- doit f2 0x6ed9eba1 (m 21) e a b c d
113 (c, e) <- doit f2 0x6ed9eba1 (m 22) d e a b c
114 (b, d) <- doit f2 0x6ed9eba1 (m 23) c d e a b
115 (a, c) <- doit f2 0x6ed9eba1 (m 24) b c d e a
116 (e, b) <- doit f2 0x6ed9eba1 (m 25) a b c d e
117 (d, a) <- doit f2 0x6ed9eba1 (m 26) e a b c d
118 (c, e) <- doit f2 0x6ed9eba1 (m 27) d e a b c
119 (b, d) <- doit f2 0x6ed9eba1 (m 28) c d e a b
120 (a, c) <- doit f2 0x6ed9eba1 (m 29) b c d e a
121 (e, b) <- doit f2 0x6ed9eba1 (m 30) a b c d e
122 (d, a) <- doit f2 0x6ed9eba1 (m 31) e a b c d
123 (c, e) <- doit f2 0x6ed9eba1 (m 32) d e a b c
124 (b, d) <- doit f2 0x6ed9eba1 (m 33) c d e a b
125 (a, c) <- doit f2 0x6ed9eba1 (m 34) b c d e a
126 (e, b) <- doit f2 0x6ed9eba1 (m 35) a b c d e
127 (d, a) <- doit f2 0x6ed9eba1 (m 36) e a b c d
128 (c, e) <- doit f2 0x6ed9eba1 (m 37) d e a b c
129 (b, d) <- doit f2 0x6ed9eba1 (m 38) c d e a b
130 (a, c) <- doit f2 0x6ed9eba1 (m 39) b c d e a
131 (e, b) <- doit f3 0x8f1bbcdc (m 40) a b c d e
132 (d, a) <- doit f3 0x8f1bbcdc (m 41) e a b c d
133 (c, e) <- doit f3 0x8f1bbcdc (m 42) d e a b c
134 (b, d) <- doit f3 0x8f1bbcdc (m 43) c d e a b
135 (a, c) <- doit f3 0x8f1bbcdc (m 44) b c d e a
136 (e, b) <- doit f3 0x8f1bbcdc (m 45) a b c d e
137 (d, a) <- doit f3 0x8f1bbcdc (m 46) e a b c d
138 (c, e) <- doit f3 0x8f1bbcdc (m 47) d e a b c
139 (b, d) <- doit f3 0x8f1bbcdc (m 48) c d e a b
140 (a, c) <- doit f3 0x8f1bbcdc (m 49) b c d e a
141 (e, b) <- doit f3 0x8f1bbcdc (m 50) a b c d e
142 (d, a) <- doit f3 0x8f1bbcdc (m 51) e a b c d
143 (c, e) <- doit f3 0x8f1bbcdc (m 52) d e a b c
144 (b, d) <- doit f3 0x8f1bbcdc (m 53) c d e a b
145 (a, c) <- doit f3 0x8f1bbcdc (m 54) b c d e a
146 (e, b) <- doit f3 0x8f1bbcdc (m 55) a b c d e
147 (d, a) <- doit f3 0x8f1bbcdc (m 56) e a b c d
148 (c, e) <- doit f3 0x8f1bbcdc (m 57) d e a b c
149 (b, d) <- doit f3 0x8f1bbcdc (m 58) c d e a b
150 (a, c) <- doit f3 0x8f1bbcdc (m 59) b c d e a
151 (e, b) <- doit f2 0xca62c1d6 (m 60) a b c d e
152 (d, a) <- doit f2 0xca62c1d6 (m 61) e a b c d
153 (c, e) <- doit f2 0xca62c1d6 (m 62) d e a b c
154 (b, d) <- doit f2 0xca62c1d6 (m 63) c d e a b
155 (a, c) <- doit f2 0xca62c1d6 (m 64) b c d e a
156 (e, b) <- doit f2 0xca62c1d6 (m 65) a b c d e
157 (d, a) <- doit f2 0xca62c1d6 (m 66) e a b c d
158 (c, e) <- doit f2 0xca62c1d6 (m 67) d e a b c
159 (b, d) <- doit f2 0xca62c1d6 (m 68) c d e a b
160 (a, c) <- doit f2 0xca62c1d6 (m 69) b c d e a
161 (e, b) <- doit f2 0xca62c1d6 (m 70) a b c d e
162 (d, a) <- doit f2 0xca62c1d6 (m 71) e a b c d
163 (c, e) <- doit f2 0xca62c1d6 (m 72) d e a b c
164 (b, d) <- doit f2 0xca62c1d6 (m 73) c d e a b
165 (a, c) <- doit f2 0xca62c1d6 (m 74) b c d e a
166 (e, b) <- doit f2 0xca62c1d6 (m 75) a b c d e
167 (d, a) <- doit f2 0xca62c1d6 (m 76) e a b c d
168 (c, e) <- doit f2 0xca62c1d6 (m 77) d e a b c
169 (b, d) <- doit f2 0xca62c1d6 (m 78) c d e a b
170 (a, c) <- doit f2 0xca62c1d6 (m 79) b c d e a
171 let abcde' = ABCDE (a0 + a) (b0 + b) (c0 + c) (d0 + d) (e0 + e)
172 sha1_step_4_main abcde' (s `advancePtr` 16) (len - 64)
173 where {-# INLINE f1 #-}
174 f1 (XYZ x y z) = (x .&. y) .|. ((complement x) .&. z)
176 f2 (XYZ x y z) = x `xor` y `xor` z
178 f3 (XYZ x y z) = (x .&. y) .|. (x .&. z) .|. (y .&. z)
180 x n = peek (s `advancePtr` n)
182 m n = do let base = s `advancePtr` (n .&. 15)
184 x1 <- peek (s `advancePtr` ((n - 14) .&. 15))
185 x2 <- peek (s `advancePtr` ((n - 8) .&. 15))
186 x3 <- peek (s `advancePtr` ((n - 3) .&. 15))
187 let res = rotateL (x0 `xor` x1 `xor` x2 `xor` x3) 1
191 doit f k i a b c d e = a `seq` c `seq`
193 return (rotateL a 5 + f (XYZ b c d) + e + i' + k,
196 sha1_step_5_display :: ABCDE -> String
197 sha1_step_5_display (ABCDE a b c d e)
198 = concatMap showAsHex [a, b, c, d, e]
200 showAsHex :: Word32 -> String
201 showAsHex n = showIt 8 n ""
203 showIt :: Int -> Word32 -> String -> String
205 showIt i x r = case quotRem x 16 of
206 (y, z) -> let c = intToDigit (fromIntegral z)
207 in c `seq` showIt (i-1) y (c:r)