chiark / gitweb /
Expunge revision histories in files.
[catacomb] / pss.c
1 /* -*-c-*-
2  *
3  * $Id: pss.c,v 1.2 2004/04/08 01:36:15 mdw Exp $
4  *
5  * Probabistic signature scheme
6  *
7  * (c) 2000 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of Catacomb.
13  *
14  * Catacomb is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * Catacomb is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with Catacomb; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Header files ------------------------------------------------------*/
31
32 #include <string.h>
33
34 #include <mLib/alloc.h>
35 #include <mLib/bits.h>
36 #include <mLib/dstr.h>
37
38 #include "gcipher.h"
39 #include "ghash.h"
40 #include "grand.h"
41 #include "rsa.h"
42
43 /*----- Magic statics -----------------------------------------------------*/
44
45 static const octet z8[8] = { 0 };
46
47 /*----- Main code ---------------------------------------------------------*/
48
49 /* --- @pss_encode@ --- *
50  *
51  * Arguments:   @mp *d@ = where to put the answer
52  *              @const void *m@ = pointer to the message hash
53  *              @size_t msz@ = the size of the message hash
54  *              @octet *b@ = scratch buffer
55  *              @size_t sz@ = sizeo of the buffer (large enough)
56  *              @unsigned long nbits@ = size in bits of @n@
57  *              @void *p@ = pointer to the PSS parameters
58  *
59  * Returns:     Encoded message representative, or null on error.
60  *
61  * Use:         Implements the operation @EMSA-PSS-ENCODE@, as defined in
62  *              PKCS#1 v. 2.1 (RFC3447).
63  */
64
65 mp *pss_encode(mp *d, const void *m, size_t msz, octet *b, size_t sz,
66                unsigned long nbits, void *p)
67 {
68   pss *pp = p;
69   octet *s, *r;
70   ghash *h;
71   gcipher *c;
72   unsigned mask;
73   size_t pssz, hsz = pp->ch->hashsz;
74
75   /* --- Check the message length --- */
76
77   nbits--;
78   sz = (nbits + 7)/8;
79   mask = (1 << nbits%8) - 1;
80   if (!mask) mask = 0xff;
81   if (hsz + pp->ssz + 2 > sz)
82     return (0);
83
84   /* --- Generate a random salt --- */
85
86   pssz = sz - pp->ssz - hsz - 2;
87   memset(b, 0, pssz);
88   b[pssz] = 0x01;
89   s = b + pssz + 1;
90   r = s + pp->ssz;
91   GR_FILL(pp->r, s, pp->ssz);
92
93   /* --- Compute the salted hash --- */
94
95   h = GH_INIT(pp->ch);
96   GH_HASH(h, z8, 8);
97   GH_HASH(h, m, msz);
98   GH_HASH(h, s, pp->ssz);
99   GH_DONE(h, r);
100   r[hsz] = 0xbc;
101
102   /* --- Do the masking --- */
103
104   c = GC_INIT(pp->cc, r, hsz);
105   GC_ENCRYPT(c, b, b, pssz + pp->ssz + 1);
106   GC_DESTROY(c);
107   b[0] &= mask;
108   return (mp_loadb(d, b, sz));
109 }
110
111 /* --- @pss_decode@ --- *
112  *
113  * Arguments:   @mp *s@ = the message representative
114  *              @const void *m@ = the original message
115  *              @size_t msz@ = the message size
116  *              @octet *b@ = a scratch buffer
117  *              @size_t sz@ = size of the buffer (large enough)
118  *              @unsigned long nbits@ = number of bits in @n@
119  *              @void *p@ = pointer to PKCS1 parameters
120  *
121  * Returns:     The length of the output string if successful, negative on
122  *              failure.
123  *
124  * Use:         Implements the operation @EMSA_PSS_VERIFY@, as defined in
125  *              PCSK#1 v. 2.1 (RFC3447).
126  */
127
128 int pss_decode(mp *mi, const void *m, size_t msz, octet *b, size_t sz,
129                unsigned long nbits, void *p)
130 {
131   pss *pp = p;
132   octet *s, *r;
133   ghash *h;
134   gcipher *c;
135   unsigned mask;
136   size_t pssz, hsz = pp->ch->hashsz, i;
137   int rc;
138
139   /* --- Check the message length --- */
140
141   nbits--;
142   sz = (nbits + 7)/8;
143   if (mp_octets(mi) > sz)
144     return (-1);
145   mask = (1 << nbits%8) - 1;
146   if (!mask) mask = 0xff;
147   if (hsz + pp->ssz + 2 > sz)
148     return (-1);
149   mp_storeb(mi, b, sz);
150
151   /* --- Split up the buffer --- */
152
153   pssz = sz - hsz - pp->ssz - 2;
154   s = b + pssz + 1;
155   r = s + pp->ssz;
156   if (r[hsz] != 0xbc)
157     return (-1);
158
159   /* --- Decode the seed --- */
160
161   if (b[0] & ~mask)
162     return (-1);
163   c = GC_INIT(pp->cc, r, hsz);
164   GC_DECRYPT(c, b, b, pssz + pp->ssz + 1);
165   GC_DESTROY(c);
166   b[0] &= mask;
167   for (i = 0; i < pssz; i++)
168     if (b[i]) return (-1);
169   if (b[pssz] != 0x01)
170     return (-1);
171
172   /* --- Hash the message --- */
173
174   h = GH_INIT(pp->ch);
175   GH_HASH(h, z8, 8);
176   GH_HASH(h, m, msz);
177   GH_HASH(h, s, pp->ssz);
178   s = GH_DONE(h, 0);
179   rc = !memcmp(s, r, hsz);
180   GH_DESTROY(h);
181   if (!rc) return (-1);
182
183   /* --- Done --- */
184
185   return (0);
186 }
187
188 /*----- That's all, folks -------------------------------------------------*/