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