fix
[elisp/flim.git] / digest-md5.el
1 ;;; digest-md5.el --- Compute DIGEST-MD5.
2
3 ;; Copyright (C) 1999 Kenichi OKADA
4
5 ;; Author: Kenichi OKADA <okada@opaopa.org>
6 ;;      Daiki Ueno <ueno@ueda.info.waseda.ac.jp>
7 ;; Keywords: DIGEST-MD5, HMAC-MD5, SASL, IMAP, POP, ACAP
8
9 ;; This file is part of FLIM (Faithful Library about Internet Message).
10
11 ;; This program is free software; you can redistribute it and/or
12 ;; modify it under the terms of the GNU General Public License as
13 ;; published by the Free Software Foundation; either version 2, or
14 ;; (at your option) any later version.
15
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with this program; see the file COPYING.  If not, write to
23 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
25
26 ;;; Commentary:
27
28 ;; This program is implemented from draft-leach-digest-sasl-05.txt.
29 ;;
30 ;; It is caller's responsibility to base64-decode challenges and
31 ;; base64-encode responses in IMAP4 AUTHENTICATE command.
32 ;;
33 ;; Passphrase should be longer than 16 bytes. (See RFC 2195)
34
35 ;; Examples.
36 ;;
37 ;; (digest-md5-parse-digest-challenge 
38 ;;   "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8")
39 ;; => (realm "elwood.innosoft.com" nonce "OA6MG9tEQGm2hh" qop "auth" algorithm md5-sess charset utf-8)
40
41 ;; (digest-md5-build-response-value
42 ;;   "chris" "secret" "OA6MHXh6VqTrRk" "imap/elwood.innosoft.com")
43 ;; => "d388dad90d4bbd760a152321f2143af7"
44
45 ;;; Code:
46
47 (require 'hmac-md5)
48 (require 'unique-id)
49
50 (defvar digest-md5-challenge nil)
51
52 (defvar digest-md5-parse-digest-challenge-syntax-table
53   (let ((table (make-syntax-table)))
54     (modify-syntax-entry ?= "." table)
55     (modify-syntax-entry ?, "." table)
56     table)
57   "A syntax table for parsing digest-challenge attributes.")
58
59 ;;;###autoload
60 (defun digest-md5-parse-digest-challenge (digest-challenge)
61   ;; return a property list of 
62   ;; (realm nonce qop-options stale maxbuf charset 
63   ;; algorithm cipher-opts auth-param).
64   (with-temp-buffer
65     (set-syntax-table digest-md5-parse-digest-challenge-syntax-table)
66     (insert digest-challenge)
67     (goto-char (point-min))
68     (insert "(")
69     (while (progn (forward-sexp) (not (eobp)))
70       (delete-char 1)
71       (insert " "))
72     (insert ")")
73     (condition-case nil
74         (setplist 'digest-md5-challenge (read (point-min-marker)))
75       (end-of-file
76        (error "Parse error in digest-challenge.")))))
77
78 (defun digest-md5-digest-uri (serv-type host &optional serv-name)
79   (concat serv-type "/" host
80           (if (and serv-name
81                    (null (string= host serv-name)))
82               (concat "/" serv-name))))
83
84 (defmacro digest-md5-cnonce ()
85   ;; It is RECOMMENDED that it 
86   ;; contain at least 64 bits of entropy.
87   '(concat (unique-id-m "") (unique-id-m "")))
88
89 (defmacro digest-md5-challenge (prop)
90   (list 'get ''digest-md5-challenge prop))
91
92 (defmacro digest-md5-build-response-value
93   (username realm passwd nonce cnonce nonce-count digest-uri qop)
94   `(encode-hex-string
95     (md5-binary
96      (concat
97       (encode-hex-string
98        (md5-binary (concat (md5-binary 
99                             (concat ,username 
100                                     ":" ,realm
101                                     ":" ,passwd))
102                            ":" ,nonce
103                            ":" ,cnonce
104                            (let ((authzid (digest-md5-challenge 'authzid)))
105                              (if authzid (concat ":" authzid) nil)))))
106       ":" ,nonce
107       ":" (format "%08x" ,nonce-count) ":" ,cnonce ":" ,qop ":"
108       (encode-hex-string
109        (md5-binary
110         (concat "AUTHENTICATE:" ,digest-uri
111                 (if (string-equal "auth-int" ,qop)
112                     ":00000000000000000000000000000000"
113                   nil))))))))
114
115 ;;;###autoload
116 (defun digest-md5-digest-response
117   (username realm passwd nonce cnonce nonce-count digest-uri
118             &optional charset qop maxbuf cipher authzid)
119   (concat
120    "username=\"" username "\","
121    "realm=\"" realm "\","
122    "nonce=\"" nonce "\","
123    (format "nc=%08x," nonce-count)
124    "cnonce=\"" cnonce "\","
125    "digest-uri=\"" digest-uri "\","
126    "response=" 
127    (digest-md5-build-response-value
128     username realm passwd nonce cnonce nonce-count digest-uri
129     (or qop "auth"))
130    ","
131    (mapconcat 
132     #'identity
133     (delq nil 
134           (mapcar (lambda (prop)
135                     (if (digest-md5-challenge prop)
136                         (format "%s=%s"
137                                 prop (digest-md5-challenge prop))))
138                   '(charset qop maxbuf cipher authzid)))
139     ",")))
140   
141 (provide 'digest-md5)
142
143 ;;; digest-md5.el ends here