1 ;;; sha1-old.el -- SHA-1 message digest algorithm
3 ;; Copyright (C) 1998 Ray Jones
5 ;; Author: Ray Jones, rjones@pobox.com
6 ;; Keywords: SHA, SHA-1, message digest
9 ;; This program is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program; if not, you can either send email to this
21 ;; program's maintainer or write to: The Free Software Foundation,
22 ;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
26 ;; this is a slower, more clear, version of sha1.el. it's based on
27 ;; md5-old.el, since much of the code is similar. however, SHA-1 is
28 ;; different than MD5 in that MD5 treats the input bits as MSB-first
29 ;; bitwise but LSB-first bytewise, but SHA-1 treats the data as
30 ;; MSB-first both bit- and byte-wise.
36 "return the sha1 hash of a string, as a 128 bit string"
37 (let* ((length (length string))
38 ;; sha1 requires the message be padded to a length of 512*k +
39 ;; 64 (bits). confusion source: we're working with bytes.
41 ;; padding is always done.
42 ;; 512 bits = 64 bytes, 64 bits = 8 bytes
43 (next-512 (+ 64 (logand (+ length 8) (lognot 63))))
44 (pad-bytes (- next-512 length 8))
45 (pad-string (make-string pad-bytes 0))
46 (len-string (make-string 8 0)))
47 ;; message is constructed as:
48 ;; original-message | pad | length-in-bits
49 ;; pad is 10000... (bitwise)
50 ;; length-in-bits is length before padding, and is 64 bits long
52 ;; fill in the single bit of the pad
53 (aset pad-string 0 (ash 1 7))
55 ;; there's a slim chance of overflow when multiplying the length
56 ;; by 8 to get the length in bits. to avoid this, do some
57 ;; slightly hairier math when writing the length into len-string.
60 (aset len-string (+ 4 idx) (logand #xff
61 (ash length (+ -21 (* 8 idx))))))
64 (sha1-string-to-32bit-vec
65 (concat string pad-string len-string)))))
67 (defun sha1-string-to-32bit-vec (string)
68 ;; emacs doesn't actually have 32 bits, in most implementations.
69 ;; 32 bit numbers are represented as a pair of 16 bit numbers
71 ;; 4 chars per 32 bit number, MSB-first
72 (let* ((veclen (/ (length string) 4))
73 (vec (make-vector veclen nil))
75 (dotimes (vecidx veclen)
76 ;; SHA-1 integers are (hi . lo) 16 bit words
77 (aset vec vecidx (cons (+ (ash (aref string (+ stridx 0)) 8)
78 (aref string (+ stridx 1)))
79 (+ (ash (aref string (+ stridx 2)) 8)
80 (aref string (+ stridx 3)))))
86 (defsubst sha1-f1-2 (x y z)
91 ;; f for rounds 20-39 and 60-79
92 (defsubst sha1-f2&4-2 (x y z)
96 (defsubst sha1-f3-2 (x y z)
102 (defsubst sha1-f1 (x y z)
103 (cons (sha1-f1-2 (car x) (car y) (car z))
104 (sha1-f1-2 (cdr x) (cdr y) (cdr z))))
106 (defsubst sha1-f2&4 (x y z)
107 (cons (sha1-f2&4-2 (car x) (car y) (car z))
108 (sha1-f2&4-2 (cdr x) (cdr y) (cdr z))))
110 (defsubst sha1-f3 (x y z)
111 (cons (sha1-f3-2 (car x) (car y) (car z))
112 (sha1-f3-2 (cdr x) (cdr y) (cdr z))))
114 (defsubst sha1<<< (val shift)
115 "circular shift sha1 32 bit int VAL by 1 bit"
118 ;; only three cases ever occur
119 (cond ((= shift 1) (cons (logand #xffff (logior (ash a 1) (ash b -15)))
120 (logand #xffff (logior (ash b 1) (ash a -15)))))
121 ((= shift 5) (cons (logand #xffff (logior (ash a 5) (ash b -11)))
122 (logand #xffff (logior (ash b 5) (ash a -11)))))
123 ;; shift = 30, which is a swap and a shift by 14
124 (t (cons (logand #xffff (logior (ash b 14) (ash a -2)))
125 (logand #xffff (logior (ash a 14) (ash b -2))))))))
127 (defsubst sha1+ (&rest args)
128 ;; since we only use 16 bits, there's enough room to just add
129 ;; without carry checks for each add.
130 (let* ((lo (apply #'+ (mapcar #'cdr args)))
131 (hi (+ (ash lo -16) (apply #'+ (mapcar #'car args)))))
132 (cons (logand #xffff hi)
133 (logand #xffff lo))))
135 (defsubst sha1-logxor4 (a b c d)
136 (cons (logxor (car a) (car b) (car c) (car d))
137 (logxor (cdr a) (cdr b) (cdr c) (cdr d))))
139 (defmacro sha1-rewrite (fun k)
140 "helper function for sha1-vector, below. ugly coding practice,
141 having a macro-rewriter elsewhere, but the indentation was getting a
143 NB: many variables must be defined at the calling point!"
144 `(let ((temp (sha1+ (sha1<<< a 5)
157 (defun sha1-vector (vec)
158 ;; initialize the chaining variables
159 (let ((a (cons #x6745 #x2301))
160 (b (cons #xefcd #xab89))
161 (c (cons #x98ba #xdcfe))
162 (d (cons #x1032 #x5476))
163 (e (cons #xc3d2 #xe1f0))
164 (w (make-vector 80 0))
167 (dotimes (count (/ (length vec) 16))
170 (aset w idx (aref vec (+ v-offset idx))))
172 ;; fill in the rest of w
173 (do ((idx 16 (1+ idx)))
175 (aset w idx (sha1<<< (sha1-logxor4 (aref w (- idx 3))
181 (let ((AA a) (BB b) (CC c) (DD d) (EE e)
185 ;; (insert (format "%s %s %s %s %s\n"
187 (sha1-rewrite sha1-f1 '(#x5a82 . #x7999)))
190 (sha1-rewrite sha1-f2&4 '(#x6ed9 . #xeba1)))
193 (sha1-rewrite sha1-f3 '(#x8f1b . #xbcdc)))
196 (sha1-rewrite sha1-f2&4 '(#xca62 . #xc1d6)))
206 ;; write out the concatenation of the state
207 (mapconcat #'(lambda (x) (format "%04x" x))
208 (list (car a) (cdr a)