chiark / gitweb /
Merge branch '2.4.x' into 2.5.x
[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
36 #include "gcipher.h"
37 #include "ghash.h"
38 #include "grand.h"
39 #include "rsa.h"
40
41 /*----- Magic statics -----------------------------------------------------*/
42
43 static const octet z8[8] = { 0 };
44
45 /*----- Main code ---------------------------------------------------------*/
46
47 /* --- @pss_encode@ --- *
48  *
49  * Arguments:   @mp *d@ = where to put the answer
50  *              @const void *m@ = pointer to the message hash
51  *              @size_t msz@ = the size of the message hash
52  *              @octet *b@ = scratch buffer
53  *              @size_t sz@ = sizeo of the buffer (large enough)
54  *              @unsigned long nbits@ = size in bits of @n@
55  *              @void *p@ = pointer to the PSS parameters
56  *
57  * Returns:     Encoded message representative, or null on error.
58  *
59  * Use:         Implements the operation @EMSA-PSS-ENCODE@, as defined in
60  *              PKCS#1 v. 2.1 (RFC3447).
61  */
62
63 mp *pss_encode(mp *d, const void *m, size_t msz, octet *b, size_t sz,
64                unsigned long nbits, void *p)
65 {
66   pss *pp = p;
67   octet *s, *r;
68   ghash *h;
69   gcipher *c;
70   unsigned mask;
71   size_t pssz, hsz = pp->ch->hashsz;
72
73   /* --- Check the message length --- */
74
75   nbits--;
76   sz = (nbits + 7)/8;
77   mask = (1 << nbits%8) - 1;
78   if (!mask) mask = 0xff;
79   if (hsz + pp->ssz + 2 > sz)
80     return (0);
81
82   /* --- Generate a random salt --- */
83
84   pssz = sz - pp->ssz - hsz - 2;
85   memset(b, 0, pssz);
86   b[pssz] = 0x01;
87   s = b + pssz + 1;
88   r = s + pp->ssz;
89   GR_FILL(pp->r, s, pp->ssz);
90
91   /* --- Compute the salted hash --- */
92
93   h = GH_INIT(pp->ch);
94   GH_HASH(h, z8, 8);
95   GH_HASH(h, m, msz);
96   GH_HASH(h, s, pp->ssz);
97   GH_DONE(h, r);
98   r[hsz] = 0xbc;
99
100   /* --- Do the masking --- */
101
102   c = GC_INIT(pp->cc, r, hsz);
103   GC_ENCRYPT(c, b, b, pssz + pp->ssz + 1);
104   GC_DESTROY(c);
105   b[0] &= mask;
106   return (mp_loadb(d, b, sz));
107 }
108
109 /* --- @pss_decode@ --- *
110  *
111  * Arguments:   @mp *s@ = the message representative
112  *              @const void *m@ = the original message
113  *              @size_t msz@ = the message size
114  *              @octet *b@ = a scratch buffer
115  *              @size_t sz@ = size of the buffer (large enough)
116  *              @unsigned long nbits@ = number of bits in @n@
117  *              @void *p@ = pointer to PKCS1 parameters
118  *
119  * Returns:     The length of the output string if successful, negative on
120  *              failure.
121  *
122  * Use:         Implements the operation @EMSA_PSS_VERIFY@, as defined in
123  *              PCSK#1 v. 2.1 (RFC3447).
124  */
125
126 int pss_decode(mp *mi, const void *m, size_t msz, octet *b, size_t sz,
127                unsigned long nbits, void *p)
128 {
129   pss *pp = p;
130   octet *s, *r;
131   ghash *h;
132   gcipher *c;
133   unsigned mask;
134   size_t pssz, hsz = pp->ch->hashsz, i;
135   int rc;
136
137   /* --- Check the message length --- */
138
139   nbits--;
140   sz = (nbits + 7)/8;
141   if (mp_octets(mi) > sz)
142     return (-1);
143   mask = (1 << nbits%8) - 1;
144   if (!mask) mask = 0xff;
145   if (hsz + pp->ssz + 2 > sz)
146     return (-1);
147   mp_storeb(mi, b, sz);
148
149   /* --- Split up the buffer --- */
150
151   pssz = sz - hsz - pp->ssz - 2;
152   s = b + pssz + 1;
153   r = s + pp->ssz;
154   if (r[hsz] != 0xbc)
155     return (-1);
156
157   /* --- Decode the seed --- */
158
159   if (b[0] & ~mask)
160     return (-1);
161   c = GC_INIT(pp->cc, r, hsz);
162   GC_DECRYPT(c, b, b, pssz + pp->ssz + 1);
163   GC_DESTROY(c);
164   b[0] &= mask;
165   for (i = 0; i < pssz; i++)
166     if (b[i]) return (-1);
167   if (b[pssz] != 0x01)
168     return (-1);
169
170   /* --- Hash the message --- */
171
172   h = GH_INIT(pp->ch);
173   GH_HASH(h, z8, 8);
174   GH_HASH(h, m, msz);
175   GH_HASH(h, s, pp->ssz);
176   s = GH_DONE(h, 0);
177   rc = !memcmp(s, r, hsz);
178   GH_DESTROY(h);
179   if (!rc) return (-1);
180
181   /* --- Done --- */
182
183   return (0);
184 }
185
186 /*----- That's all, folks -------------------------------------------------*/