summaryrefslogtreecommitdiffstats
path: root/contrib/pgcrypto/pgp-s2k.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pgcrypto/pgp-s2k.c')
-rw-r--r--contrib/pgcrypto/pgp-s2k.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/contrib/pgcrypto/pgp-s2k.c b/contrib/pgcrypto/pgp-s2k.c
new file mode 100644
index 0000000..81ca1f0
--- /dev/null
+++ b/contrib/pgcrypto/pgp-s2k.c
@@ -0,0 +1,308 @@
+/*
+ * pgp-s2k.c
+ * OpenPGP string2key functions.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-s2k.c
+ */
+
+#include "postgres.h"
+
+#include "pgp.h"
+#include "px.h"
+
+static int
+calc_s2k_simple(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
+ unsigned key_len)
+{
+ unsigned md_rlen;
+ uint8 buf[PGP_MAX_DIGEST];
+ unsigned preload;
+ unsigned remain;
+ uint8 *dst = s2k->key;
+
+ md_rlen = px_md_result_size(md);
+
+ remain = s2k->key_len;
+ preload = 0;
+ while (remain > 0)
+ {
+ px_md_reset(md);
+
+ if (preload)
+ {
+ memset(buf, 0, preload);
+ px_md_update(md, buf, preload);
+ }
+ preload++;
+
+ px_md_update(md, key, key_len);
+ px_md_finish(md, buf);
+
+ if (remain > md_rlen)
+ {
+ memcpy(dst, buf, md_rlen);
+ dst += md_rlen;
+ remain -= md_rlen;
+ }
+ else
+ {
+ memcpy(dst, buf, remain);
+ remain = 0;
+ }
+ }
+ px_memset(buf, 0, sizeof(buf));
+ return 0;
+}
+
+static int
+calc_s2k_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, unsigned key_len)
+{
+ unsigned md_rlen;
+ uint8 buf[PGP_MAX_DIGEST];
+ unsigned preload = 0;
+ uint8 *dst;
+ unsigned remain;
+
+ md_rlen = px_md_result_size(md);
+
+ dst = s2k->key;
+ remain = s2k->key_len;
+ while (remain > 0)
+ {
+ px_md_reset(md);
+
+ if (preload > 0)
+ {
+ memset(buf, 0, preload);
+ px_md_update(md, buf, preload);
+ }
+ preload++;
+
+ px_md_update(md, s2k->salt, PGP_S2K_SALT);
+ px_md_update(md, key, key_len);
+ px_md_finish(md, buf);
+
+ if (remain > md_rlen)
+ {
+ memcpy(dst, buf, md_rlen);
+ remain -= md_rlen;
+ dst += md_rlen;
+ }
+ else
+ {
+ memcpy(dst, buf, remain);
+ remain = 0;
+ }
+ }
+ px_memset(buf, 0, sizeof(buf));
+ return 0;
+}
+
+static int
+calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
+ unsigned key_len)
+{
+ unsigned md_rlen;
+ uint8 buf[PGP_MAX_DIGEST];
+ uint8 *dst;
+ unsigned preload = 0;
+ unsigned remain,
+ c,
+ curcnt,
+ count;
+
+ count = s2k_decode_count(s2k->iter);
+
+ md_rlen = px_md_result_size(md);
+
+ remain = s2k->key_len;
+ dst = s2k->key;
+ while (remain > 0)
+ {
+ px_md_reset(md);
+
+ if (preload)
+ {
+ memset(buf, 0, preload);
+ px_md_update(md, buf, preload);
+ }
+ preload++;
+
+ px_md_update(md, s2k->salt, PGP_S2K_SALT);
+ px_md_update(md, key, key_len);
+ curcnt = PGP_S2K_SALT + key_len;
+
+ while (curcnt < count)
+ {
+ if (curcnt + PGP_S2K_SALT < count)
+ c = PGP_S2K_SALT;
+ else
+ c = count - curcnt;
+ px_md_update(md, s2k->salt, c);
+ curcnt += c;
+
+ if (curcnt + key_len < count)
+ c = key_len;
+ else if (curcnt < count)
+ c = count - curcnt;
+ else
+ break;
+ px_md_update(md, key, c);
+ curcnt += c;
+ }
+ px_md_finish(md, buf);
+
+ if (remain > md_rlen)
+ {
+ memcpy(dst, buf, md_rlen);
+ remain -= md_rlen;
+ dst += md_rlen;
+ }
+ else
+ {
+ memcpy(dst, buf, remain);
+ remain = 0;
+ }
+ }
+ px_memset(buf, 0, sizeof(buf));
+ return 0;
+}
+
+/*
+ * Decide PGP_S2K_ISALTED iteration count (in OpenPGP one-byte representation)
+ *
+ * Too small: weak
+ * Too big: slow
+ * gpg defaults to 96 => 65536 iters
+ *
+ * For our default (count=-1) we let it float a bit: 96 + 32 => between 65536
+ * and 262144 iterations.
+ *
+ * Otherwise, find the smallest number which provides at least the specified
+ * iteration count.
+ */
+static uint8
+decide_s2k_iter(unsigned rand_byte, int count)
+{
+ int iter;
+
+ if (count == -1)
+ return 96 + (rand_byte & 0x1F);
+ /* this is a bit brute-force, but should be quick enough */
+ for (iter = 0; iter <= 255; iter++)
+ if (s2k_decode_count(iter) >= count)
+ return iter;
+ return 255;
+}
+
+int
+pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count)
+{
+ int res = 0;
+ uint8 tmp;
+
+ s2k->mode = mode;
+ s2k->digest_algo = digest_algo;
+
+ switch (s2k->mode)
+ {
+ case PGP_S2K_SIMPLE:
+ break;
+ case PGP_S2K_SALTED:
+ if (!pg_strong_random(s2k->salt, PGP_S2K_SALT))
+ return PXE_NO_RANDOM;
+ break;
+ case PGP_S2K_ISALTED:
+ if (!pg_strong_random(s2k->salt, PGP_S2K_SALT))
+ return PXE_NO_RANDOM;
+ if (!pg_strong_random(&tmp, 1))
+ return PXE_NO_RANDOM;
+ s2k->iter = decide_s2k_iter(tmp, count);
+ break;
+ default:
+ res = PXE_PGP_BAD_S2K_MODE;
+ }
+ return res;
+}
+
+int
+pgp_s2k_read(PullFilter *src, PGP_S2K *s2k)
+{
+ int res = 0;
+
+ GETBYTE(src, s2k->mode);
+ GETBYTE(src, s2k->digest_algo);
+ switch (s2k->mode)
+ {
+ case 0:
+ break;
+ case 1:
+ res = pullf_read_fixed(src, 8, s2k->salt);
+ break;
+ case 3:
+ res = pullf_read_fixed(src, 8, s2k->salt);
+ if (res < 0)
+ break;
+ GETBYTE(src, s2k->iter);
+ break;
+ default:
+ res = PXE_PGP_BAD_S2K_MODE;
+ }
+ return res;
+}
+
+int
+pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int key_len)
+{
+ int res;
+ PX_MD *md;
+
+ s2k->key_len = pgp_get_cipher_key_size(cipher);
+ if (s2k->key_len <= 0)
+ return PXE_PGP_UNSUPPORTED_CIPHER;
+
+ res = pgp_load_digest(s2k->digest_algo, &md);
+ if (res < 0)
+ return res;
+
+ switch (s2k->mode)
+ {
+ case 0:
+ res = calc_s2k_simple(s2k, md, key, key_len);
+ break;
+ case 1:
+ res = calc_s2k_salted(s2k, md, key, key_len);
+ break;
+ case 3:
+ res = calc_s2k_iter_salted(s2k, md, key, key_len);
+ break;
+ default:
+ res = PXE_PGP_BAD_S2K_MODE;
+ }
+ px_md_free(md);
+ return res;
+}