Re: [openpgp] Deriving an OpenPGP secret key from a human readable seed

Phillip Hallam-Baker <phill@hallambaker.com> Sat, 19 October 2019 18:23 UTC

Return-Path: <hallam@gmail.com>
X-Original-To: openpgp@ietfa.amsl.com
Delivered-To: openpgp@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 3439C120059 for <openpgp@ietfa.amsl.com>; Sat, 19 Oct 2019 11:23:02 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: 0.251
X-Spam-Level:
X-Spam-Status: No, score=0.251 tagged_above=-999 required=5 tests=[FREEMAIL_FORGED_FROMDOMAIN=0.001, FREEMAIL_FROM=0.001, HEADER_FROM_DIFFERENT_DOMAINS=0.249, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=no autolearn_force=no
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Lt66Bml1EL1G for <openpgp@ietfa.amsl.com>; Sat, 19 Oct 2019 11:23:00 -0700 (PDT)
Received: from mail-oi1-f178.google.com (mail-oi1-f178.google.com [209.85.167.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id D5013120018 for <openpgp@ietf.org>; Sat, 19 Oct 2019 11:22:59 -0700 (PDT)
Received: by mail-oi1-f178.google.com with SMTP id w6so7857522oie.11 for <openpgp@ietf.org>; Sat, 19 Oct 2019 11:22:59 -0700 (PDT)
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=ncACYY4eBH4GCRPjqVDtCI/pdubHjxadHdtoBp+5Wf8=; b=Lw322V8k2ayszrhibhLuSvarmp5oGLRqovfh1OOuDpbTbIxwU2kXnnSeuTxqhJvHxH XqDq8seE/2O2X9yKTtJDCfdz4iG/cu27syJ7dCwBLO5i4kANqNUGn3VeawOf/YBoeYHx HOT+p1/gK5e1MiNDV70NUK7ZfHX+wgvDeQt62ux9bq0LanyXDV68hjLjv3uS6NgPSYci Q3WH7MOqKC3wpmHhv4h1wp6xY8MdhE/OW24R+CvXxg5MCCOB4DzwHH2j3NwMuu9aK+zE IiFEGjgPpMF45/0zMKHU3t0MEEzA+dhEypNGEHLNo35ak1lR0kBkswUqn+azqW+LCs4f YBBA==
X-Gm-Message-State: APjAAAU0XoHx8ULIBQL6NM+4JRgIB61rYGfoy3LMr3+TCPg8rWYcr+Uc HBrmgs/M28BNrgcIBKEE1uWvpLp0r1BNIn7uXXy/sH4FW9w=
X-Google-Smtp-Source: APXvYqwCnpxqtSt14bfQIUyL4ibrOdk9jjbPgxgrl2WfkZgV2i2tok8hVUbbemivqyfVf5fMmoHWW/iE+KuI0Ec+LyE=
X-Received: by 2002:aca:4a49:: with SMTP id x70mr13075595oia.17.1571509378867; Sat, 19 Oct 2019 11:22:58 -0700 (PDT)
MIME-Version: 1.0
References: <5eb8774d-8d4f-63e3-29bc-53f3c8d21c51@kuix.de> <FAAB5286-1C26-4F32-AB76-8B1E2C93FA77@icloud.com> <2efcd737-34b3-00bb-527f-725daf6e8509@kuix.de> <20191018225100.bnslptroeenuusxf@camp.crustytoothpaste.net> <CAMm+LwhL7ys67J=TaLwWDFEpb91H5SwQChVuoaHHqmCsoTiQjg@mail.gmail.com> <20191019044008.othhw7j5fktqxdta@camp.crustytoothpaste.net> <CAMm+LwjRN6fhvZK+oSb6NLZvLK+QHuxn0oF7Mez3Eodb0sbJ4g@mail.gmail.com> <13025.1571490248@localhost>
In-Reply-To: <13025.1571490248@localhost>
From: Phillip Hallam-Baker <phill@hallambaker.com>
Date: Sat, 19 Oct 2019 14:22:54 -0400
Message-ID: <CAMm+Lwg1uiHco8YSkXUPTOvf2+u+jz9+nqkA=T0MwnVus_LzOQ@mail.gmail.com>
To: Michael Richardson <mcr+ietf@sandelman.ca>
Cc: IETF OpenPGP <openpgp@ietf.org>
Content-Type: multipart/alternative; boundary="00000000000049e4860595478a4e"
Archived-At: <https://mailarchive.ietf.org/arch/msg/openpgp/aKks28CJddW8xKBNyhKt_xlcA8E>
Subject: Re: [openpgp] Deriving an OpenPGP secret key from a human readable seed
X-BeenThere: openpgp@ietf.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: "Ongoing discussion of OpenPGP issues." <openpgp.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/openpgp>, <mailto:openpgp-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/openpgp/>
List-Post: <mailto:openpgp@ietf.org>
List-Help: <mailto:openpgp-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/openpgp>, <mailto:openpgp-request@ietf.org?subject=subscribe>
X-List-Received-Date: Sat, 19 Oct 2019 18:23:02 -0000

OK so I have not implemented DSA but it turns out that it the spec mandates
the entire process:
https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf

The main consequence of DSA is that it mandates the entire process
including prime generation *and* provides a mechanism for validation of all
the parameters.

This discussion now has me thinking that we should have been validating
parameters for RSA before importing them into an application all along.


On Sat, Oct 19, 2019 at 9:04 AM Michael Richardson <mcr+ietf@sandelman.ca>
wrote:

>
> Phillip Hallam-Baker <phill@hallambaker.com> wrote:
>     > Right now, my feeling is that if someone is going to use a broken
> primality
>     > test, the risk of not recovering their key might be the least of
> their
>     > concerns...
>
> Yes, but the issue is bugs.
>
> If someone fixes (or introduces...) a bug in a primality test, then I might
> recover a different key.  This doesn't happen if I generate and key the
> private key.
>
> If I lose my system and I install a new system, the odds of new/patched
> software compared to when I first generated is high.
>

Absolutely!

And I can provide a recovery mechanism that does just that. So the set of
requirements I see are:

A) Generation/Import of keypairs meeting BCP criteria of NIST and IETF from
fingerprint
B) Identification of faulty implementations
C) Recovery of mis-generated key pairs.
D) Verifiable generation processes with separation of duties.

It is not necessary for every implementation to do all of these. An SSH /
OpenPGP / S/MIME app only needs to implement A and allow B and only if it
actually implements keygen at all.

I can meet the full set of requirements with the Mesh management tool. This
is open source, MIT license. The code for the UDF stuff is not complicated
though. Concentrating all the key management functions in a single app
allows them to be done better and more comprehensively.

*A) Generate*

The commands for generating, exporting and importing a key from the CLI
would probably look something like the following. Since I am thinking of
the general case, the key fingerprints used as UDF content digests rather
than OpenPGP but this is largely because it was easier to cut and paste
from my docs rather than find another.

> myapp generate alice@example.com --udf
Generated key:  MB5S-R4AJ-3FBT-7NHO-T26Z-2E6Y-WFH4
Ready.
> myapp export alice@example.com --udf
ZAEA-AWMQ-6Z4O-RRMM-Y72J-CGWI-ZC7L-V5Y
Ready.
> myapp import alice@example.com
--udf=ZAEA-AWMQ-6Z4O-RRMM-Y72J-CGWI-ZC7L-V5Y
Ready.

*B) Detecting a faulty key*

myapp import alice@example.com
--udf=ZAEA-AWMQ-6Z4O-RRMM-Y72J-CGWI-ZC7L-V5Y
--check=MB5S-R4AJ-3FBT-7NHO-T26Z-2E6Y-ZZZZ
Error-ABEND-0243: Recovered key did not match

We can get a better test of the generated key checking with a different
application

mesh verify ZAEA-AWMQ-6Z4O-RRMM-Y72J-CGWI-ZC7L-V5Y
MB5S-R4AJ-3FBT-7NHO-T26Z-2E6Y-WFH4
WARNING: Key does not match

*C) Recovery of mis-generated key pairs*

Recovery of a misgenerated key pair is easiest if we know the modulus. In
that case we can generate the starting points for the primality search for
either P or Q and then just do trial divisions until we get a exact match.
So the first thing the mesh recovery tool would do is to attempt to obtain
the public key parameters from the fingerprint.

If we only have the fingerprint, we have to assume at least one of the
parameters is prime, generate a trial key for each prime candidate in the
search and test to see if it matches the fingerprint:
> mesh recover ZAEA-AWMQ-6Z4O-RRMM-Y72J-CGWI-ZC7L-V5Y
MB5S-R4AJ-3FBT-7NHO-T26Z-2E6Y-WFH4
WARNING: Key recovered is NOT SECURE
Primality testing failed.
Recovered key written to MB5S-R4AJ-3FBT-7NHO-T26Z-2E6Y-WFH4.p12

*D) Verifiable generation processes with separation of duties. *

NB: This is not the sort of process I see many individuals performing for
themselves. But it is exactly the sort of procedure I might want to use as
the basis for separation of duties in a key ceremony type situation. Every
one of the input shares affects every bit of the output. The splitting (but
not the generated key!) is information theoretic secure.

UDF gives us the ability to use Shamir secret sharing to split a secret. We
can also use this in reverse to create a secret from random contributions
generated on separate machines.

So let us imagine we begin by generating the following nonce values on
independent machines.
NAQC-GKXI-6DTJ-COKM-4HBF-CZJJ-BO6G-I
NAED-CRXH-IASE-5ZYS-ZS2D-PQT4-6O6P-G
NCRB-6YXF-R5RA-ZFGY-W6TB-4H6Q-3O6Y-E

We can combine them to form a single secret for a specific purpose. Since
we need to encode some information into the first three bytes of the result
and we have one type code, we have 32 bits fixed in the output:

ZAAQ-AWMQ-6Z4O-RRMM-Y72J-CGWI-ZC7L

We can now generate a set of Shamir secrets that closely resemble but are
not exactly the same as our nonce inputs:

SAEC-GKXI-6DTJ-COKM-4HBF-CZJJ-BO6G-I
SAED-CRXH-IASE-5ZYS-ZS2D-PQT4-6O6P-G
SAMB-R3XF-R5RA-ZFGY-W6TB-4H6Q-3O6Y-E

Note that only the first three characters of the first two shares and the
first six characters of the last changed here.

We can verify that the above secrets combine to create ZAAQ-AWMQ-... and we
can even generate additional shares if we so choose. We can't change the
quorum unless we reshare the secret.

So now imagine we are generating these from QR codes being read by a
camera. We run the scheme some number of times with full observability.
Then we cover one of the inputs so the observers can only see the other
three and run the system some randomly chosen number of times with a
different input covered on each round.