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 -fno-warn-name-shadowing #-}
21 -- {-# OPTIONS_GHC -fglasgow-exts -fno-warn-name-shadowing #-}
22 -- -fglasgow-exts needed for nasty hack below
23 -- name shadowing disabled because a,b,c,d,e are shadowed loads in step 4
24 module SHA1 (sha1PS) where
26 import Autoconf (big_endian)
27 import ByteStringUtils (unsafeWithInternals)
28 import qualified Data.ByteString as B (ByteString, pack, length, concat)
30 import Control.Monad (unless)
31 import Data.Char (intToDigit)
32 import Data.Bits (xor, (.&.), (.|.), complement, rotateL, shiftL, shiftR)
33 import Data.Word (Word8, Word32)
34 import Foreign.Ptr (Ptr, castPtr)
35 import Foreign.Marshal.Array (advancePtr)
36 import Foreign.Storable (peek, poke)
37 import System.IO.Unsafe (unsafePerformIO)
39 data ABCDE = ABCDE !Word32 !Word32 !Word32 !Word32 !Word32
40 data XYZ = XYZ !Word32 !Word32 !Word32
42 sha1PS :: B.ByteString -> String
44 where s1_2 = sha1_step_1_2_pad_length s
45 abcde = sha1_step_3_init
46 abcde' = unsafePerformIO
47 $ unsafeWithInternals s1_2 (\ptr len ->
48 do let ptr' = castPtr ptr
49 unless big_endian $ fiddle_endianness ptr' len
50 sha1_step_4_main abcde ptr' len)
51 s5 = sha1_step_5_display abcde'
53 fiddle_endianness :: Ptr Word32 -> Int -> IO ()
54 fiddle_endianness p 0 = p `seq` return ()
58 .|. shiftL (x .&. 0xff00) 8
59 .|. (shiftR x 8 .&. 0xff00)
61 fiddle_endianness (p `advancePtr` 1) (n - 4)
64 sha1_step_1_2_pad_length assumes the length is at most 2^61.
65 This seems reasonable as the Int used to represent it is normally 32bit,
66 but obviously could go wrong with large inputs on 64bit machines.
67 The B.ByteString library should probably move to Word64s if this is an
71 sha1_step_1_2_pad_length :: B.ByteString -> B.ByteString
72 sha1_step_1_2_pad_length s
73 = let len = B.length s
74 num_nuls = (55 - len) `mod` 64
75 padding = 128:replicate num_nuls 0
76 len_w8s = reverse $ size_split 8 (fromIntegral len*8)
77 in B.concat [s, B.pack padding, B.pack len_w8s]
79 size_split :: Int -> Integer -> [Word8]
81 size_split p n = fromIntegral d:size_split (p-1) n'
82 where (n', d) = divMod n 256
84 sha1_step_3_init :: ABCDE
85 sha1_step_3_init = ABCDE 0x67452301 0xefcdab89 0x98badcfe 0x10325476 0xc3d2e1f0
89 sha1_step_4_main :: ABCDE -> Ptr Word32 -> Int -> IO ABCDE
90 sha1_step_4_main abcde _ 0 = return $! abcde
91 sha1_step_4_main (ABCDE a0@a b0@b c0@c d0@d e0@e) s len
93 (e, b) <- doit f1 0x5a827999 (x 0) a b c d e
94 (d, a) <- doit f1 0x5a827999 (x 1) e a b c d
95 (c, e) <- doit f1 0x5a827999 (x 2) d e a b c
96 (b, d) <- doit f1 0x5a827999 (x 3) c d e a b
97 (a, c) <- doit f1 0x5a827999 (x 4) b c d e a
98 (e, b) <- doit f1 0x5a827999 (x 5) a b c d e
99 (d, a) <- doit f1 0x5a827999 (x 6) e a b c d
100 (c, e) <- doit f1 0x5a827999 (x 7) d e a b c
101 (b, d) <- doit f1 0x5a827999 (x 8) c d e a b
102 (a, c) <- doit f1 0x5a827999 (x 9) b c d e a
103 (e, b) <- doit f1 0x5a827999 (x 10) a b c d e
104 (d, a) <- doit f1 0x5a827999 (x 11) e a b c d
105 (c, e) <- doit f1 0x5a827999 (x 12) d e a b c
106 (b, d) <- doit f1 0x5a827999 (x 13) c d e a b
107 (a, c) <- doit f1 0x5a827999 (x 14) b c d e a
108 (e, b) <- doit f1 0x5a827999 (x 15) a b c d e
109 (d, a) <- doit f1 0x5a827999 (m 16) e a b c d
110 (c, e) <- doit f1 0x5a827999 (m 17) d e a b c
111 (b, d) <- doit f1 0x5a827999 (m 18) c d e a b
112 (a, c) <- doit f1 0x5a827999 (m 19) b c d e a
113 (e, b) <- doit f2 0x6ed9eba1 (m 20) a b c d e
114 (d, a) <- doit f2 0x6ed9eba1 (m 21) e a b c d
115 (c, e) <- doit f2 0x6ed9eba1 (m 22) d e a b c
116 (b, d) <- doit f2 0x6ed9eba1 (m 23) c d e a b
117 (a, c) <- doit f2 0x6ed9eba1 (m 24) b c d e a
118 (e, b) <- doit f2 0x6ed9eba1 (m 25) a b c d e
119 (d, a) <- doit f2 0x6ed9eba1 (m 26) e a b c d
120 (c, e) <- doit f2 0x6ed9eba1 (m 27) d e a b c
121 (b, d) <- doit f2 0x6ed9eba1 (m 28) c d e a b
122 (a, c) <- doit f2 0x6ed9eba1 (m 29) b c d e a
123 (e, b) <- doit f2 0x6ed9eba1 (m 30) a b c d e
124 (d, a) <- doit f2 0x6ed9eba1 (m 31) e a b c d
125 (c, e) <- doit f2 0x6ed9eba1 (m 32) d e a b c
126 (b, d) <- doit f2 0x6ed9eba1 (m 33) c d e a b
127 (a, c) <- doit f2 0x6ed9eba1 (m 34) b c d e a
128 (e, b) <- doit f2 0x6ed9eba1 (m 35) a b c d e
129 (d, a) <- doit f2 0x6ed9eba1 (m 36) e a b c d
130 (c, e) <- doit f2 0x6ed9eba1 (m 37) d e a b c
131 (b, d) <- doit f2 0x6ed9eba1 (m 38) c d e a b
132 (a, c) <- doit f2 0x6ed9eba1 (m 39) b c d e a
133 (e, b) <- doit f3 0x8f1bbcdc (m 40) a b c d e
134 (d, a) <- doit f3 0x8f1bbcdc (m 41) e a b c d
135 (c, e) <- doit f3 0x8f1bbcdc (m 42) d e a b c
136 (b, d) <- doit f3 0x8f1bbcdc (m 43) c d e a b
137 (a, c) <- doit f3 0x8f1bbcdc (m 44) b c d e a
138 (e, b) <- doit f3 0x8f1bbcdc (m 45) a b c d e
139 (d, a) <- doit f3 0x8f1bbcdc (m 46) e a b c d
140 (c, e) <- doit f3 0x8f1bbcdc (m 47) d e a b c
141 (b, d) <- doit f3 0x8f1bbcdc (m 48) c d e a b
142 (a, c) <- doit f3 0x8f1bbcdc (m 49) b c d e a
143 (e, b) <- doit f3 0x8f1bbcdc (m 50) a b c d e
144 (d, a) <- doit f3 0x8f1bbcdc (m 51) e a b c d
145 (c, e) <- doit f3 0x8f1bbcdc (m 52) d e a b c
146 (b, d) <- doit f3 0x8f1bbcdc (m 53) c d e a b
147 (a, c) <- doit f3 0x8f1bbcdc (m 54) b c d e a
148 (e, b) <- doit f3 0x8f1bbcdc (m 55) a b c d e
149 (d, a) <- doit f3 0x8f1bbcdc (m 56) e a b c d
150 (c, e) <- doit f3 0x8f1bbcdc (m 57) d e a b c
151 (b, d) <- doit f3 0x8f1bbcdc (m 58) c d e a b
152 (a, c) <- doit f3 0x8f1bbcdc (m 59) b c d e a
153 (e, b) <- doit f2 0xca62c1d6 (m 60) a b c d e
154 (d, a) <- doit f2 0xca62c1d6 (m 61) e a b c d
155 (c, e) <- doit f2 0xca62c1d6 (m 62) d e a b c
156 (b, d) <- doit f2 0xca62c1d6 (m 63) c d e a b
157 (a, c) <- doit f2 0xca62c1d6 (m 64) b c d e a
158 (e, b) <- doit f2 0xca62c1d6 (m 65) a b c d e
159 (d, a) <- doit f2 0xca62c1d6 (m 66) e a b c d
160 (c, e) <- doit f2 0xca62c1d6 (m 67) d e a b c
161 (b, d) <- doit f2 0xca62c1d6 (m 68) c d e a b
162 (a, c) <- doit f2 0xca62c1d6 (m 69) b c d e a
163 (e, b) <- doit f2 0xca62c1d6 (m 70) a b c d e
164 (d, a) <- doit f2 0xca62c1d6 (m 71) e a b c d
165 (c, e) <- doit f2 0xca62c1d6 (m 72) d e a b c
166 (b, d) <- doit f2 0xca62c1d6 (m 73) c d e a b
167 (a, c) <- doit f2 0xca62c1d6 (m 74) b c d e a
168 (e, b) <- doit f2 0xca62c1d6 (m 75) a b c d e
169 (d, a) <- doit f2 0xca62c1d6 (m 76) e a b c d
170 (c, e) <- doit f2 0xca62c1d6 (m 77) d e a b c
171 (b, d) <- doit f2 0xca62c1d6 (m 78) c d e a b
172 (a, c) <- doit f2 0xca62c1d6 (m 79) b c d e a
173 let abcde' = ABCDE (a0 + a) (b0 + b) (c0 + c) (d0 + d) (e0 + e)
174 sha1_step_4_main abcde' (s `advancePtr` 16) (len - 64)
175 where {-# INLINE f1 #-}
176 f1 (XYZ x y z) = (x .&. y) .|. ((complement x) .&. z)
178 f2 (XYZ x y z) = x `xor` y `xor` z
180 f3 (XYZ x y z) = (x .&. y) .|. (x .&. z) .|. (y .&. z)
182 x n = peek (s `advancePtr` n)
184 m n = do let base = s `advancePtr` (n .&. 15)
186 x1 <- peek (s `advancePtr` ((n - 14) .&. 15))
187 x2 <- peek (s `advancePtr` ((n - 8) .&. 15))
188 x3 <- peek (s `advancePtr` ((n - 3) .&. 15))
189 let res = rotateL (x0 `xor` x1 `xor` x2 `xor` x3) 1
193 doit f k i a b c d e = a `seq` c `seq`
195 return (rotateL a 5 + f (XYZ b c d) + e + i' + k,
198 sha1_step_5_display :: ABCDE -> String
199 sha1_step_5_display (ABCDE a b c d e)
200 = concatMap showAsHex [a, b, c, d, e]
202 showAsHex :: Word32 -> String
203 showAsHex n = showIt 8 n ""
205 showIt :: Int -> Word32 -> String -> String
207 showIt i x r = case quotRem x 16 of
208 (y, z) -> let c = intToDigit (fromIntegral z)
209 in c `seq` showIt (i-1) y (c:r)