View in color | License | Download script | History | Other scripts by: luce80 |
30-Apr 15:59 UTC
[0.066] 19.337k
[0.066] 19.337k
sha2.rREBOL [
Title: "SHA2 Message-Digest Algorithm"
Author: "Marco Antoniazzi"
file: %sha2.r
email: [luce80 AT libero DOT it]
date: 22-03-2013
version: 1.0.0
Purpose: {Returns a sha2 "message digest" of an input string as a binary!}
History: [
1.0.0 [22-03-2013 "Started and finished"]
]
library: [
level: 'intermediate
platform: 'all
type: 'tool
domain: [encryption]
tested-under: [View 2.7.8.3.1]
support: none
License: "http://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License"
]
Notes: {
taken from: FIPS 180-4
taken from: http://en.wikipedia.org/wiki/sha-2
Not fast but compact
NO WARRANTIES. USE AT YOUR OWN RISK.
Bugs: length of message must be < 2^63 bytes
}
]
ctx-sha2: context [
; convenience functions
int-to-bin: func [num [integer!]][debase/base to-hex num 16] ; big-endian
to-uint32: func [num [decimal!]][while [num < 0] [num: num + 4294967296] while [num > 2147483647] [num: num - 4294967296] to integer! num]
rightrotate: func [x [integer!] c [integer!]] [
(shift/logical x c) or shift/left/logical x (32 - c)
]
rightshift: func [x [integer!] c [integer!]] [
shift/logical x c
]
;Note 1: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating
;Note 2: All constants in this code are in big endian.
; Within each word, the most significant byte is stored in the leftmost byte position
set 'sha2 func [[catch]
{Returns a SHA2 "message digest" of the input string as binary!}
message [any-string!] "input string"
/sha-224 "Returns a SHA-224"
/sha-256 "Returns a SHA-256 (this is the default)"
/with sha2-context [block!] "initial context"
/local
final-length
a b c d e f g h
i j w-t w
h0 h1 h2 h3 h4 h5 h6 h7
ch s0 s1 maj byte
temp pad?
][
message: to-binary message
k: [
1116352408 1899447441 -1245643825 -373957723 961987163 1508970993 -1841331548 -1424204075
-670586216 310598401 607225278 1426881987 1925078388 -2132889090 -1680079193 -1046744716
-459576895 -272742522 264347078 604807628 770255983 1249150122 1555081692 1996064986
-1740746414 -1473132947 -1341970488 -1084653625 -958395405 -710438585 113926993 338241895
666307205 773529912 1294757372 1396182291 1695183700 1986661051 -2117940946 -1838011259
-1564481375 -1474664885 -1035236496 -949202525 -778901479 -694614492 -200395387 275423344
430227734 506948616 659060556 883997877 958139571 1322822218 1537002063 1747873779
1955562222 2024104815 -2067236844 -1933114872 -1866530822 -1538233109 -1090935817 -965641998
]
final-length: round/ceiling/to (length? message) + 1 + 8 64 ; At least 1 byte for padding single 1 bit and 8 bytes for message length (in bits)
temp: length? message
pad?: true
either none? sha2-context [
sha2-context: copy [0 0 0 0 0 0 0 0 0]
][
if 9 <> length? sha2-context [throw make error! "sha2-context length must be 6"]
if sha2-context/1 = 0 [
if 0 <> mod temp 64 [throw make error! "message length must be a multiple of 64 bytes"]
final-length: temp
pad?: false
]
]
either sha2-context/1 = 0 [
temp: 8.0 * temp ; length in bits of message
either sha-224 [
sha2-context/2: -1056596264
sha2-context/3: 914150663
sha2-context/4: 812702999
sha2-context/5: -150054599
sha2-context/6: -4191439
sha2-context/7: 1750603025
sha2-context/8: 1694076839
sha2-context/9: -1090891868
][
sha2-context/2: 1779033703
sha2-context/3: -1150833019
sha2-context/4: 1013904242
sha2-context/5: -1521486534
sha2-context/6: 1359893119
sha2-context/7: -1694144372
sha2-context/8: 528734635
sha2-context/9: 1541459225
]
][
temp: 8 * temp + sha2-context/1
]
i: to-integer temp / 4294967296 ; high 32 bits
j: to-integer temp - (i * 4294967296) ; low 32 bits
sha2-context/1: temp
if pad? [
;Step 1. Append Padding Bits
;Pre-processing:
;append the bit '1' to the message
insert tail message #{80} ; padding single 1 bit
;append 0 = k < 512 bits '0', so that the resulting message length (in bits)
; is congruent to 448 (mod 512)
insert/dup tail message #{00} final-length - (length? message) - 8
;Step 2. Append Length
;append length of message (before pre-processing), in bits, as 64-bit big-endian integer
message: head insert tail message join int-to-bin i int-to-bin j 2
]
;Step 3. Initialize main Buffer
;Initialize variables:
h0: sha2-context/2
h1: sha2-context/3
h2: sha2-context/4
h3: sha2-context/5
h4: sha2-context/6
h5: sha2-context/7
h6: sha2-context/8
h7: sha2-context/9
;Step 4. Process Message in 16-Word Blocks
w: array 64
;Process the message in successive 512-bit chunks:
;break message into 512-bit chunks
for byte 1 final-length 64 [
;break chunk into sixteen 32-bit big-endian words w[i], 0 <= i <= 15
w-t: at message byte
;Extend the sixteen 32-bit words into eighty 32-bit words:
for i 1 64 1 [
either i <= 16 [
w/(i): to integer! copy/part at w-t (i * 4 - 3) 4
][
s0: (rightrotate w/(i - 15) 7) xor (rightrotate w/(i - 15) 18) xor (rightshift w/(i - 15) 3)
s1: (rightrotate w/(i - 2) 17) xor (rightrotate w/(i - 2) 19) xor (rightshift w/(i - 2) 10)
w/(i): to-uint32 0.0 + w/(i - 16) + s0 + w/(i - 7) + s1
]
]
;Initialize hash value for this chunk:
a: h0
b: h1
c: h2
d: h3
e: h4
f: h5
g: h6
h: h7
;Main loop:
for i 1 64 1 [
S1: (rightrotate e 6) xor (rightrotate e 11) xor (rightrotate e 25)
ch: (e and f) xor ((complement e) and g)
temp: 0.0 + h + S1 + ch + k/:i + w/:i
d: to-uint32 d + temp
S0: (rightrotate a 2) xor (rightrotate a 13) xor (rightrotate a 22)
maj: (a and (b xor c)) xor (b and c)
temp: to-uint32 0.0 + temp + S0 + maj
h: g
g: f
f: e
e: d
d: c
c: b
b: a
a: temp
]
;Add this chunk's hash to result so far:
h0: to-uint32 0.0 + h0 + a
h1: to-uint32 0.0 + h1 + b
h2: to-uint32 0.0 + h2 + c
h3: to-uint32 0.0 + h3 + d
h4: to-uint32 0.0 + h4 + e
h5: to-uint32 0.0 + h5 + f
h6: to-uint32 0.0 + h6 + g
h7: to-uint32 0.0 + h7 + h
]
sha2-context/2: h0
sha2-context/3: h1
sha2-context/4: h2
sha2-context/5: h3
sha2-context/6: h4
sha2-context/7: h5
sha2-context/8: h6
sha2-context/9: h7
;Step 5. Output ;
;Produce the final hash value (big-endian):
temp: rejoin [int-to-bin h0 int-to-bin h1 int-to-bin h2 int-to-bin h3 int-to-bin h4 int-to-bin h5 int-to-bin h6 either sha-224 [#{}][int-to-bin h7] ]
]
]
hmac: func [
hasher [function!] {hashing function}
text [any-string!] { data stream }
key [any-string!] { authentication key }
/local
k_ipad
k_opad
i
][
k_ipad: copy #{} { inner padding - key XORd with ipad}
k_opad: copy #{} { outer padding - key XORd with opad}
if (length? key) > 64 [key: copy/part hasher key 64]
; XOR key with ipad and opad values
for i 1 64 1 [
insert tail k_ipad to-char (any [key/:i 0]) xor 54
insert tail k_opad to-char (any [key/:i 0]) xor 92
]
hasher join k_opad hasher join k_ipad text
]
;comment [
do [
probe sha2/sha-224 ""
probe sha2 "abc"
probe sha2 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
probe sha2 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
sha2-ctx: [0 0 0 0 0 0 0 0 0] ; initialize sha2 context
sha2/with "1234567890123456789012345678901234567890123456789012345678901234" sha2-ctx
probe sha2/with "5678901234567890" sha2-ctx
probe hmac :sha2 #{5361 6D706C65 206D6573 73616765 20666F72 206B6579 6C656E3C 626C6F63 6B6C656E} #{00010203 04050607 08090A0B 0C0D0E0F 10111213 14151617 18191A1B 1C1D1E1F}
halt
] |