* Switch to keybase go-crypto (for some elliptic curve key) + test
* Use assert.NoError
and add a little more context to failing test description
* Use assert.(No)Error everywhere 🌈
and assert.Error in place of .Nil/.NotNil
tags/v1.21.12.1
| @@ -19,9 +19,9 @@ import ( | |||
| "code.gitea.io/gitea/modules/log" | |||
| "github.com/go-xorm/xorm" | |||
| "golang.org/x/crypto/openpgp" | |||
| "golang.org/x/crypto/openpgp/armor" | |||
| "golang.org/x/crypto/openpgp/packet" | |||
| "github.com/keybase/go-crypto/openpgp" | |||
| "github.com/keybase/go-crypto/openpgp/armor" | |||
| "github.com/keybase/go-crypto/openpgp/packet" | |||
| ) | |||
| // GPGKey represents a GPG key. | |||
| @@ -43,7 +43,28 @@ MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg== | |||
| -----END PGP PUBLIC KEY BLOCK-----` | |||
| key, err := checkArmoredGPGKeyString(testGPGArmor) | |||
| assert.Nil(t, err, "Could not parse a valid GPG armored key", key) | |||
| assert.NoError(t, err, "Could not parse a valid GPG public armored rsa key", key) | |||
| //TODO verify value of key | |||
| } | |||
| func TestCheckArmoredbrainpoolP256r1GPGKeyString(t *testing.T) { | |||
| testGPGArmor := `-----BEGIN PGP PUBLIC KEY BLOCK----- | |||
| Version: GnuPG v2 | |||
| mFMEV6HwkhMJKyQDAwIIAQEHAgMEUsvJO/j5dFMRRj67qeZC9fSKBsGZdOHRj2+6 | |||
| 8wssmbUuLTfT/ZjIbExETyY8hFnURRGpD2Ifyz0cKjXcbXfJtrQTRm9vYmFyIDxm | |||
| b29AYmFyLmRlPoh/BBMTCAAnBQJZOsDIAhsDBQkJZgGABQsJCAcCBhUICQoLAgQW | |||
| AgMBAh4BAheAAAoJEGuJTd/DBMzmNVQA/2beUrv1yU4gyvCiPDEm3pK42cSfaL5D | |||
| muCtPCUg9hlWAP4yq6M78NW8STfsXgn6oeziMYiHSTmV14nOamLuwwDWM7hXBFeh | |||
| 8JISCSskAwMCCAEBBwIDBG3A+XfINAZp1CTse2mRNgeUE5DbUtEpO8ALXKA1UQsQ | |||
| DLKq27b7zTgawgXIGUGP6mWsJ5oH7MNAJ/uKTsYmX40DAQgHiGcEGBMIAA8FAleh | |||
| 8JICGwwFCQlmAYAACgkQa4lN38MEzOZwKAD/QKyerAgcvzzLaqvtap3XvpYcw9tc | |||
| OyjLLnFQiVmq7kEA/0z0CQe3ZQiQIq5zrs7Nh1XRkFAo8GlU/SGC9XFFi722 | |||
| =ZiSe | |||
| -----END PGP PUBLIC KEY BLOCK-----` | |||
| key, err := checkArmoredGPGKeyString(testGPGArmor) | |||
| assert.NoError(t, err, "Could not parse a valid GPG public armored brainpoolP256r1 key", key) | |||
| //TODO verify value of key | |||
| } | |||
| @@ -79,11 +100,11 @@ MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg== | |||
| =i9b7 | |||
| -----END PGP PUBLIC KEY BLOCK-----` | |||
| ekey, err := checkArmoredGPGKeyString(testGPGArmor) | |||
| assert.Nil(t, err, "Could not parse a valid GPG armored key", ekey) | |||
| assert.NoError(t, err, "Could not parse a valid GPG armored key", ekey) | |||
| pubkey := ekey.PrimaryKey | |||
| content, err := base64EncPubKey(pubkey) | |||
| assert.Nil(t, err, "Could not base64 encode a valid PublicKey content", ekey) | |||
| assert.NoError(t, err, "Could not base64 encode a valid PublicKey content", ekey) | |||
| key := &GPGKey{ | |||
| KeyID: pubkey.KeyIdString(), | |||
| @@ -144,21 +165,21 @@ Unknown GPG key with good email | |||
| ` | |||
| //Reading Sign | |||
| goodSig, err := extractSignature(testGoodSigArmor) | |||
| assert.Nil(t, err, "Could not parse a valid GPG armored signature", testGoodSigArmor) | |||
| assert.NoError(t, err, "Could not parse a valid GPG armored signature", testGoodSigArmor) | |||
| badSig, err := extractSignature(testBadSigArmor) | |||
| assert.Nil(t, err, "Could not parse a valid GPG armored signature", testBadSigArmor) | |||
| assert.NoError(t, err, "Could not parse a valid GPG armored signature", testBadSigArmor) | |||
| //Generating hash of commit | |||
| goodHash, err := populateHash(goodSig.Hash, []byte(testGoodPayload)) | |||
| assert.Nil(t, err, "Could not generate a valid hash of payload", testGoodPayload) | |||
| assert.NoError(t, err, "Could not generate a valid hash of payload", testGoodPayload) | |||
| badHash, err := populateHash(badSig.Hash, []byte(testBadPayload)) | |||
| assert.Nil(t, err, "Could not generate a valid hash of payload", testBadPayload) | |||
| assert.NoError(t, err, "Could not generate a valid hash of payload", testBadPayload) | |||
| //Verify | |||
| err = verifySign(goodSig, goodHash, key) | |||
| assert.Nil(t, err, "Could not validate a good signature") | |||
| assert.NoError(t, err, "Could not validate a good signature") | |||
| err = verifySign(badSig, badHash, key) | |||
| assert.NotNil(t, err, "Validate a bad signature") | |||
| assert.Error(t, err, "Validate a bad signature") | |||
| err = verifySign(goodSig, goodHash, cannotsignkey) | |||
| assert.NotNil(t, err, "Validate a bad signature with a kay that can not sign") | |||
| assert.Error(t, err, "Validate a bad signature with a kay that can not sign") | |||
| } | |||
| @@ -0,0 +1,27 @@ | |||
| Copyright (c) 2009 The Go Authors. All rights reserved. | |||
| Redistribution and use in source and binary forms, with or without | |||
| modification, are permitted provided that the following conditions are | |||
| met: | |||
| * Redistributions of source code must retain the above copyright | |||
| notice, this list of conditions and the following disclaimer. | |||
| * 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. | |||
| * Neither the name of Google Inc. nor the names of its | |||
| contributors may be used to endorse or promote products derived from | |||
| this software without specific prior written permission. | |||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT | |||
| OWNER 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. | |||
| @@ -0,0 +1,22 @@ | |||
| Additional IP Rights Grant (Patents) | |||
| "This implementation" means the copyrightable works distributed by | |||
| Google as part of the Go project. | |||
| Google hereby grants to You a perpetual, worldwide, non-exclusive, | |||
| no-charge, royalty-free, irrevocable (except as stated in this section) | |||
| patent license to make, have made, use, offer to sell, sell, import, | |||
| transfer and otherwise run, modify and propagate the contents of this | |||
| implementation of Go, where such license applies only to those patent | |||
| claims, both currently owned or controlled by Google and acquired in | |||
| the future, licensable by Google that are necessarily infringed by this | |||
| implementation of Go. This grant does not include claims that would be | |||
| infringed only as a consequence of further modification of this | |||
| implementation. If you or your agent or exclusive licensee institute or | |||
| order or agree to the institution of patent litigation against any | |||
| entity (including a cross-claim or counterclaim in a lawsuit) alleging | |||
| that this implementation of Go or any code incorporated within this | |||
| implementation of Go constitutes direct or contributory patent | |||
| infringement, or inducement of patent infringement, then any patent | |||
| rights granted to you under this License for this implementation of Go | |||
| shall terminate as of the date such litigation is filed. | |||
| @@ -0,0 +1,134 @@ | |||
| // Package brainpool implements Brainpool elliptic curves. | |||
| // Implementation of rcurves is from github.com/ebfe/brainpool | |||
| // Note that these curves are implemented with naive, non-constant time operations | |||
| // and are likely not suitable for enviroments where timing attacks are a concern. | |||
| package brainpool | |||
| import ( | |||
| "crypto/elliptic" | |||
| "math/big" | |||
| "sync" | |||
| ) | |||
| var ( | |||
| once sync.Once | |||
| p256t1, p384t1, p512t1 *elliptic.CurveParams | |||
| p256r1, p384r1, p512r1 *rcurve | |||
| ) | |||
| func initAll() { | |||
| initP256t1() | |||
| initP384t1() | |||
| initP512t1() | |||
| initP256r1() | |||
| initP384r1() | |||
| initP512r1() | |||
| } | |||
| func initP256t1() { | |||
| p256t1 = &elliptic.CurveParams{Name: "brainpoolP256t1"} | |||
| p256t1.P, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16) | |||
| p256t1.N, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16) | |||
| p256t1.B, _ = new(big.Int).SetString("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16) | |||
| p256t1.Gx, _ = new(big.Int).SetString("A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4", 16) | |||
| p256t1.Gy, _ = new(big.Int).SetString("2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE", 16) | |||
| p256t1.BitSize = 256 | |||
| } | |||
| func initP256r1() { | |||
| twisted := p256t1 | |||
| params := &elliptic.CurveParams{ | |||
| Name: "brainpoolP256r1", | |||
| P: twisted.P, | |||
| N: twisted.N, | |||
| BitSize: twisted.BitSize, | |||
| } | |||
| params.Gx, _ = new(big.Int).SetString("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", 16) | |||
| params.Gy, _ = new(big.Int).SetString("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", 16) | |||
| z, _ := new(big.Int).SetString("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0", 16) | |||
| p256r1 = newrcurve(twisted, params, z) | |||
| } | |||
| func initP384t1() { | |||
| p384t1 = &elliptic.CurveParams{Name: "brainpoolP384t1"} | |||
| p384t1.P, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16) | |||
| p384t1.N, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16) | |||
| p384t1.B, _ = new(big.Int).SetString("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16) | |||
| p384t1.Gx, _ = new(big.Int).SetString("18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC", 16) | |||
| p384t1.Gy, _ = new(big.Int).SetString("25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928", 16) | |||
| p384t1.BitSize = 384 | |||
| } | |||
| func initP384r1() { | |||
| twisted := p384t1 | |||
| params := &elliptic.CurveParams{ | |||
| Name: "brainpoolP384r1", | |||
| P: twisted.P, | |||
| N: twisted.N, | |||
| BitSize: twisted.BitSize, | |||
| } | |||
| params.Gx, _ = new(big.Int).SetString("1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", 16) | |||
| params.Gy, _ = new(big.Int).SetString("8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", 16) | |||
| z, _ := new(big.Int).SetString("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C", 16) | |||
| p384r1 = newrcurve(twisted, params, z) | |||
| } | |||
| func initP512t1() { | |||
| p512t1 = &elliptic.CurveParams{Name: "brainpoolP512t1"} | |||
| p512t1.P, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16) | |||
| p512t1.N, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16) | |||
| p512t1.B, _ = new(big.Int).SetString("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16) | |||
| p512t1.Gx, _ = new(big.Int).SetString("640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA", 16) | |||
| p512t1.Gy, _ = new(big.Int).SetString("5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332", 16) | |||
| p512t1.BitSize = 512 | |||
| } | |||
| func initP512r1() { | |||
| twisted := p512t1 | |||
| params := &elliptic.CurveParams{ | |||
| Name: "brainpoolP512r1", | |||
| P: twisted.P, | |||
| N: twisted.N, | |||
| BitSize: twisted.BitSize, | |||
| } | |||
| params.Gx, _ = new(big.Int).SetString("81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", 16) | |||
| params.Gy, _ = new(big.Int).SetString("7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", 16) | |||
| z, _ := new(big.Int).SetString("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB", 16) | |||
| p512r1 = newrcurve(twisted, params, z) | |||
| } | |||
| // P256t1 returns a Curve which implements Brainpool P256t1 (see RFC 5639, section 3.4) | |||
| func P256t1() elliptic.Curve { | |||
| once.Do(initAll) | |||
| return p256t1 | |||
| } | |||
| // P256r1 returns a Curve which implements Brainpool P256r1 (see RFC 5639, section 3.4) | |||
| func P256r1() elliptic.Curve { | |||
| once.Do(initAll) | |||
| return p256r1 | |||
| } | |||
| // P384t1 returns a Curve which implements Brainpool P384t1 (see RFC 5639, section 3.6) | |||
| func P384t1() elliptic.Curve { | |||
| once.Do(initAll) | |||
| return p384t1 | |||
| } | |||
| // P384r1 returns a Curve which implements Brainpool P384r1 (see RFC 5639, section 3.6) | |||
| func P384r1() elliptic.Curve { | |||
| once.Do(initAll) | |||
| return p384r1 | |||
| } | |||
| // P512t1 returns a Curve which implements Brainpool P512t1 (see RFC 5639, section 3.7) | |||
| func P512t1() elliptic.Curve { | |||
| once.Do(initAll) | |||
| return p512t1 | |||
| } | |||
| // P512r1 returns a Curve which implements Brainpool P512r1 (see RFC 5639, section 3.7) | |||
| func P512r1() elliptic.Curve { | |||
| once.Do(initAll) | |||
| return p512r1 | |||
| } | |||
| @@ -0,0 +1,83 @@ | |||
| package brainpool | |||
| import ( | |||
| "crypto/elliptic" | |||
| "math/big" | |||
| ) | |||
| var _ elliptic.Curve = (*rcurve)(nil) | |||
| type rcurve struct { | |||
| twisted elliptic.Curve | |||
| params *elliptic.CurveParams | |||
| z *big.Int | |||
| zinv *big.Int | |||
| z2 *big.Int | |||
| z3 *big.Int | |||
| zinv2 *big.Int | |||
| zinv3 *big.Int | |||
| } | |||
| var ( | |||
| two = big.NewInt(2) | |||
| three = big.NewInt(3) | |||
| ) | |||
| func newrcurve(twisted elliptic.Curve, params *elliptic.CurveParams, z *big.Int) *rcurve { | |||
| zinv := new(big.Int).ModInverse(z, params.P) | |||
| return &rcurve{ | |||
| twisted: twisted, | |||
| params: params, | |||
| z: z, | |||
| zinv: zinv, | |||
| z2: new(big.Int).Exp(z, two, params.P), | |||
| z3: new(big.Int).Exp(z, three, params.P), | |||
| zinv2: new(big.Int).Exp(zinv, two, params.P), | |||
| zinv3: new(big.Int).Exp(zinv, three, params.P), | |||
| } | |||
| } | |||
| func (curve *rcurve) toTwisted(x, y *big.Int) (*big.Int, *big.Int) { | |||
| var tx, ty big.Int | |||
| tx.Mul(x, curve.z2) | |||
| tx.Mod(&tx, curve.params.P) | |||
| ty.Mul(y, curve.z3) | |||
| ty.Mod(&ty, curve.params.P) | |||
| return &tx, &ty | |||
| } | |||
| func (curve *rcurve) fromTwisted(tx, ty *big.Int) (*big.Int, *big.Int) { | |||
| var x, y big.Int | |||
| x.Mul(tx, curve.zinv2) | |||
| x.Mod(&x, curve.params.P) | |||
| y.Mul(ty, curve.zinv3) | |||
| y.Mod(&y, curve.params.P) | |||
| return &x, &y | |||
| } | |||
| func (curve *rcurve) Params() *elliptic.CurveParams { | |||
| return curve.params | |||
| } | |||
| func (curve *rcurve) IsOnCurve(x, y *big.Int) bool { | |||
| return curve.twisted.IsOnCurve(curve.toTwisted(x, y)) | |||
| } | |||
| func (curve *rcurve) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) { | |||
| tx1, ty1 := curve.toTwisted(x1, y1) | |||
| tx2, ty2 := curve.toTwisted(x2, y2) | |||
| return curve.fromTwisted(curve.twisted.Add(tx1, ty1, tx2, ty2)) | |||
| } | |||
| func (curve *rcurve) Double(x1, y1 *big.Int) (x, y *big.Int) { | |||
| return curve.fromTwisted(curve.twisted.Double(curve.toTwisted(x1, y1))) | |||
| } | |||
| func (curve *rcurve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) { | |||
| tx1, ty1 := curve.toTwisted(x1, y1) | |||
| return curve.fromTwisted(curve.twisted.ScalarMult(tx1, ty1, scalar)) | |||
| } | |||
| func (curve *rcurve) ScalarBaseMult(scalar []byte) (x, y *big.Int) { | |||
| return curve.fromTwisted(curve.twisted.ScalarBaseMult(scalar)) | |||
| } | |||
| @@ -4,7 +4,7 @@ | |||
| // Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common | |||
| // OpenPGP cipher. | |||
| package cast5 // import "golang.org/x/crypto/cast5" | |||
| package cast5 | |||
| import "errors" | |||
| @@ -0,0 +1,20 @@ | |||
| // Copyright 2012 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // This code was translated into a form compatible with 6a from the public | |||
| // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||
| // +build amd64,!gccgo,!appengine | |||
| DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF | |||
| GLOBL ·REDMASK51(SB), 8, $8 | |||
| DATA ·_121666_213(SB)/8, $996687872 | |||
| GLOBL ·_121666_213(SB), 8, $8 | |||
| DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA | |||
| GLOBL ·_2P0(SB), 8, $8 | |||
| DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE | |||
| GLOBL ·_2P1234(SB), 8, $8 | |||
| @@ -0,0 +1,88 @@ | |||
| // Copyright 2012 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // This code was translated into a form compatible with 6a from the public | |||
| // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||
| // +build amd64,!gccgo,!appengine | |||
| // func cswap(inout *[5]uint64, v uint64) | |||
| TEXT ·cswap(SB),7,$0 | |||
| MOVQ inout+0(FP),DI | |||
| MOVQ v+8(FP),SI | |||
| CMPQ SI,$1 | |||
| MOVQ 0(DI),SI | |||
| MOVQ 80(DI),DX | |||
| MOVQ 8(DI),CX | |||
| MOVQ 88(DI),R8 | |||
| MOVQ SI,R9 | |||
| CMOVQEQ DX,SI | |||
| CMOVQEQ R9,DX | |||
| MOVQ CX,R9 | |||
| CMOVQEQ R8,CX | |||
| CMOVQEQ R9,R8 | |||
| MOVQ SI,0(DI) | |||
| MOVQ DX,80(DI) | |||
| MOVQ CX,8(DI) | |||
| MOVQ R8,88(DI) | |||
| MOVQ 16(DI),SI | |||
| MOVQ 96(DI),DX | |||
| MOVQ 24(DI),CX | |||
| MOVQ 104(DI),R8 | |||
| MOVQ SI,R9 | |||
| CMOVQEQ DX,SI | |||
| CMOVQEQ R9,DX | |||
| MOVQ CX,R9 | |||
| CMOVQEQ R8,CX | |||
| CMOVQEQ R9,R8 | |||
| MOVQ SI,16(DI) | |||
| MOVQ DX,96(DI) | |||
| MOVQ CX,24(DI) | |||
| MOVQ R8,104(DI) | |||
| MOVQ 32(DI),SI | |||
| MOVQ 112(DI),DX | |||
| MOVQ 40(DI),CX | |||
| MOVQ 120(DI),R8 | |||
| MOVQ SI,R9 | |||
| CMOVQEQ DX,SI | |||
| CMOVQEQ R9,DX | |||
| MOVQ CX,R9 | |||
| CMOVQEQ R8,CX | |||
| CMOVQEQ R9,R8 | |||
| MOVQ SI,32(DI) | |||
| MOVQ DX,112(DI) | |||
| MOVQ CX,40(DI) | |||
| MOVQ R8,120(DI) | |||
| MOVQ 48(DI),SI | |||
| MOVQ 128(DI),DX | |||
| MOVQ 56(DI),CX | |||
| MOVQ 136(DI),R8 | |||
| MOVQ SI,R9 | |||
| CMOVQEQ DX,SI | |||
| CMOVQEQ R9,DX | |||
| MOVQ CX,R9 | |||
| CMOVQEQ R8,CX | |||
| CMOVQEQ R9,R8 | |||
| MOVQ SI,48(DI) | |||
| MOVQ DX,128(DI) | |||
| MOVQ CX,56(DI) | |||
| MOVQ R8,136(DI) | |||
| MOVQ 64(DI),SI | |||
| MOVQ 144(DI),DX | |||
| MOVQ 72(DI),CX | |||
| MOVQ 152(DI),R8 | |||
| MOVQ SI,R9 | |||
| CMOVQEQ DX,SI | |||
| CMOVQEQ R9,DX | |||
| MOVQ CX,R9 | |||
| CMOVQEQ R8,CX | |||
| CMOVQEQ R9,R8 | |||
| MOVQ SI,64(DI) | |||
| MOVQ DX,144(DI) | |||
| MOVQ CX,72(DI) | |||
| MOVQ R8,152(DI) | |||
| MOVQ DI,AX | |||
| MOVQ SI,DX | |||
| RET | |||
| @@ -0,0 +1,841 @@ | |||
| // Copyright 2013 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // We have a implementation in amd64 assembly so this code is only run on | |||
| // non-amd64 platforms. The amd64 assembly does not support gccgo. | |||
| // +build !amd64 gccgo appengine | |||
| package curve25519 | |||
| // This code is a port of the public domain, "ref10" implementation of | |||
| // curve25519 from SUPERCOP 20130419 by D. J. Bernstein. | |||
| // fieldElement represents an element of the field GF(2^255 - 19). An element | |||
| // t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 | |||
| // t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on | |||
| // context. | |||
| type fieldElement [10]int32 | |||
| func feZero(fe *fieldElement) { | |||
| for i := range fe { | |||
| fe[i] = 0 | |||
| } | |||
| } | |||
| func feOne(fe *fieldElement) { | |||
| feZero(fe) | |||
| fe[0] = 1 | |||
| } | |||
| func feAdd(dst, a, b *fieldElement) { | |||
| for i := range dst { | |||
| dst[i] = a[i] + b[i] | |||
| } | |||
| } | |||
| func feSub(dst, a, b *fieldElement) { | |||
| for i := range dst { | |||
| dst[i] = a[i] - b[i] | |||
| } | |||
| } | |||
| func feCopy(dst, src *fieldElement) { | |||
| for i := range dst { | |||
| dst[i] = src[i] | |||
| } | |||
| } | |||
| // feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0. | |||
| // | |||
| // Preconditions: b in {0,1}. | |||
| func feCSwap(f, g *fieldElement, b int32) { | |||
| var x fieldElement | |||
| b = -b | |||
| for i := range x { | |||
| x[i] = b & (f[i] ^ g[i]) | |||
| } | |||
| for i := range f { | |||
| f[i] ^= x[i] | |||
| } | |||
| for i := range g { | |||
| g[i] ^= x[i] | |||
| } | |||
| } | |||
| // load3 reads a 24-bit, little-endian value from in. | |||
| func load3(in []byte) int64 { | |||
| var r int64 | |||
| r = int64(in[0]) | |||
| r |= int64(in[1]) << 8 | |||
| r |= int64(in[2]) << 16 | |||
| return r | |||
| } | |||
| // load4 reads a 32-bit, little-endian value from in. | |||
| func load4(in []byte) int64 { | |||
| var r int64 | |||
| r = int64(in[0]) | |||
| r |= int64(in[1]) << 8 | |||
| r |= int64(in[2]) << 16 | |||
| r |= int64(in[3]) << 24 | |||
| return r | |||
| } | |||
| func feFromBytes(dst *fieldElement, src *[32]byte) { | |||
| h0 := load4(src[:]) | |||
| h1 := load3(src[4:]) << 6 | |||
| h2 := load3(src[7:]) << 5 | |||
| h3 := load3(src[10:]) << 3 | |||
| h4 := load3(src[13:]) << 2 | |||
| h5 := load4(src[16:]) | |||
| h6 := load3(src[20:]) << 7 | |||
| h7 := load3(src[23:]) << 5 | |||
| h8 := load3(src[26:]) << 4 | |||
| h9 := load3(src[29:]) << 2 | |||
| var carry [10]int64 | |||
| carry[9] = (h9 + 1<<24) >> 25 | |||
| h0 += carry[9] * 19 | |||
| h9 -= carry[9] << 25 | |||
| carry[1] = (h1 + 1<<24) >> 25 | |||
| h2 += carry[1] | |||
| h1 -= carry[1] << 25 | |||
| carry[3] = (h3 + 1<<24) >> 25 | |||
| h4 += carry[3] | |||
| h3 -= carry[3] << 25 | |||
| carry[5] = (h5 + 1<<24) >> 25 | |||
| h6 += carry[5] | |||
| h5 -= carry[5] << 25 | |||
| carry[7] = (h7 + 1<<24) >> 25 | |||
| h8 += carry[7] | |||
| h7 -= carry[7] << 25 | |||
| carry[0] = (h0 + 1<<25) >> 26 | |||
| h1 += carry[0] | |||
| h0 -= carry[0] << 26 | |||
| carry[2] = (h2 + 1<<25) >> 26 | |||
| h3 += carry[2] | |||
| h2 -= carry[2] << 26 | |||
| carry[4] = (h4 + 1<<25) >> 26 | |||
| h5 += carry[4] | |||
| h4 -= carry[4] << 26 | |||
| carry[6] = (h6 + 1<<25) >> 26 | |||
| h7 += carry[6] | |||
| h6 -= carry[6] << 26 | |||
| carry[8] = (h8 + 1<<25) >> 26 | |||
| h9 += carry[8] | |||
| h8 -= carry[8] << 26 | |||
| dst[0] = int32(h0) | |||
| dst[1] = int32(h1) | |||
| dst[2] = int32(h2) | |||
| dst[3] = int32(h3) | |||
| dst[4] = int32(h4) | |||
| dst[5] = int32(h5) | |||
| dst[6] = int32(h6) | |||
| dst[7] = int32(h7) | |||
| dst[8] = int32(h8) | |||
| dst[9] = int32(h9) | |||
| } | |||
| // feToBytes marshals h to s. | |||
| // Preconditions: | |||
| // |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | |||
| // | |||
| // Write p=2^255-19; q=floor(h/p). | |||
| // Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). | |||
| // | |||
| // Proof: | |||
| // Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. | |||
| // Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. | |||
| // | |||
| // Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). | |||
| // Then 0<y<1. | |||
| // | |||
| // Write r=h-pq. | |||
| // Have 0<=r<=p-1=2^255-20. | |||
| // Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1. | |||
| // | |||
| // Write x=r+19(2^-255)r+y. | |||
| // Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q. | |||
| // | |||
| // Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1)) | |||
| // so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q. | |||
| func feToBytes(s *[32]byte, h *fieldElement) { | |||
| var carry [10]int32 | |||
| q := (19*h[9] + (1 << 24)) >> 25 | |||
| q = (h[0] + q) >> 26 | |||
| q = (h[1] + q) >> 25 | |||
| q = (h[2] + q) >> 26 | |||
| q = (h[3] + q) >> 25 | |||
| q = (h[4] + q) >> 26 | |||
| q = (h[5] + q) >> 25 | |||
| q = (h[6] + q) >> 26 | |||
| q = (h[7] + q) >> 25 | |||
| q = (h[8] + q) >> 26 | |||
| q = (h[9] + q) >> 25 | |||
| // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. | |||
| h[0] += 19 * q | |||
| // Goal: Output h-2^255 q, which is between 0 and 2^255-20. | |||
| carry[0] = h[0] >> 26 | |||
| h[1] += carry[0] | |||
| h[0] -= carry[0] << 26 | |||
| carry[1] = h[1] >> 25 | |||
| h[2] += carry[1] | |||
| h[1] -= carry[1] << 25 | |||
| carry[2] = h[2] >> 26 | |||
| h[3] += carry[2] | |||
| h[2] -= carry[2] << 26 | |||
| carry[3] = h[3] >> 25 | |||
| h[4] += carry[3] | |||
| h[3] -= carry[3] << 25 | |||
| carry[4] = h[4] >> 26 | |||
| h[5] += carry[4] | |||
| h[4] -= carry[4] << 26 | |||
| carry[5] = h[5] >> 25 | |||
| h[6] += carry[5] | |||
| h[5] -= carry[5] << 25 | |||
| carry[6] = h[6] >> 26 | |||
| h[7] += carry[6] | |||
| h[6] -= carry[6] << 26 | |||
| carry[7] = h[7] >> 25 | |||
| h[8] += carry[7] | |||
| h[7] -= carry[7] << 25 | |||
| carry[8] = h[8] >> 26 | |||
| h[9] += carry[8] | |||
| h[8] -= carry[8] << 26 | |||
| carry[9] = h[9] >> 25 | |||
| h[9] -= carry[9] << 25 | |||
| // h10 = carry9 | |||
| // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. | |||
| // Have h[0]+...+2^230 h[9] between 0 and 2^255-1; | |||
| // evidently 2^255 h10-2^255 q = 0. | |||
| // Goal: Output h[0]+...+2^230 h[9]. | |||
| s[0] = byte(h[0] >> 0) | |||
| s[1] = byte(h[0] >> 8) | |||
| s[2] = byte(h[0] >> 16) | |||
| s[3] = byte((h[0] >> 24) | (h[1] << 2)) | |||
| s[4] = byte(h[1] >> 6) | |||
| s[5] = byte(h[1] >> 14) | |||
| s[6] = byte((h[1] >> 22) | (h[2] << 3)) | |||
| s[7] = byte(h[2] >> 5) | |||
| s[8] = byte(h[2] >> 13) | |||
| s[9] = byte((h[2] >> 21) | (h[3] << 5)) | |||
| s[10] = byte(h[3] >> 3) | |||
| s[11] = byte(h[3] >> 11) | |||
| s[12] = byte((h[3] >> 19) | (h[4] << 6)) | |||
| s[13] = byte(h[4] >> 2) | |||
| s[14] = byte(h[4] >> 10) | |||
| s[15] = byte(h[4] >> 18) | |||
| s[16] = byte(h[5] >> 0) | |||
| s[17] = byte(h[5] >> 8) | |||
| s[18] = byte(h[5] >> 16) | |||
| s[19] = byte((h[5] >> 24) | (h[6] << 1)) | |||
| s[20] = byte(h[6] >> 7) | |||
| s[21] = byte(h[6] >> 15) | |||
| s[22] = byte((h[6] >> 23) | (h[7] << 3)) | |||
| s[23] = byte(h[7] >> 5) | |||
| s[24] = byte(h[7] >> 13) | |||
| s[25] = byte((h[7] >> 21) | (h[8] << 4)) | |||
| s[26] = byte(h[8] >> 4) | |||
| s[27] = byte(h[8] >> 12) | |||
| s[28] = byte((h[8] >> 20) | (h[9] << 6)) | |||
| s[29] = byte(h[9] >> 2) | |||
| s[30] = byte(h[9] >> 10) | |||
| s[31] = byte(h[9] >> 18) | |||
| } | |||
| // feMul calculates h = f * g | |||
| // Can overlap h with f or g. | |||
| // | |||
| // Preconditions: | |||
| // |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | |||
| // |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | |||
| // | |||
| // Postconditions: | |||
| // |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | |||
| // | |||
| // Notes on implementation strategy: | |||
| // | |||
| // Using schoolbook multiplication. | |||
| // Karatsuba would save a little in some cost models. | |||
| // | |||
| // Most multiplications by 2 and 19 are 32-bit precomputations; | |||
| // cheaper than 64-bit postcomputations. | |||
| // | |||
| // There is one remaining multiplication by 19 in the carry chain; | |||
| // one *19 precomputation can be merged into this, | |||
| // but the resulting data flow is considerably less clean. | |||
| // | |||
| // There are 12 carries below. | |||
| // 10 of them are 2-way parallelizable and vectorizable. | |||
| // Can get away with 11 carries, but then data flow is much deeper. | |||
| // | |||
| // With tighter constraints on inputs can squeeze carries into int32. | |||
| func feMul(h, f, g *fieldElement) { | |||
| f0 := f[0] | |||
| f1 := f[1] | |||
| f2 := f[2] | |||
| f3 := f[3] | |||
| f4 := f[4] | |||
| f5 := f[5] | |||
| f6 := f[6] | |||
| f7 := f[7] | |||
| f8 := f[8] | |||
| f9 := f[9] | |||
| g0 := g[0] | |||
| g1 := g[1] | |||
| g2 := g[2] | |||
| g3 := g[3] | |||
| g4 := g[4] | |||
| g5 := g[5] | |||
| g6 := g[6] | |||
| g7 := g[7] | |||
| g8 := g[8] | |||
| g9 := g[9] | |||
| g1_19 := 19 * g1 // 1.4*2^29 | |||
| g2_19 := 19 * g2 // 1.4*2^30; still ok | |||
| g3_19 := 19 * g3 | |||
| g4_19 := 19 * g4 | |||
| g5_19 := 19 * g5 | |||
| g6_19 := 19 * g6 | |||
| g7_19 := 19 * g7 | |||
| g8_19 := 19 * g8 | |||
| g9_19 := 19 * g9 | |||
| f1_2 := 2 * f1 | |||
| f3_2 := 2 * f3 | |||
| f5_2 := 2 * f5 | |||
| f7_2 := 2 * f7 | |||
| f9_2 := 2 * f9 | |||
| f0g0 := int64(f0) * int64(g0) | |||
| f0g1 := int64(f0) * int64(g1) | |||
| f0g2 := int64(f0) * int64(g2) | |||
| f0g3 := int64(f0) * int64(g3) | |||
| f0g4 := int64(f0) * int64(g4) | |||
| f0g5 := int64(f0) * int64(g5) | |||
| f0g6 := int64(f0) * int64(g6) | |||
| f0g7 := int64(f0) * int64(g7) | |||
| f0g8 := int64(f0) * int64(g8) | |||
| f0g9 := int64(f0) * int64(g9) | |||
| f1g0 := int64(f1) * int64(g0) | |||
| f1g1_2 := int64(f1_2) * int64(g1) | |||
| f1g2 := int64(f1) * int64(g2) | |||
| f1g3_2 := int64(f1_2) * int64(g3) | |||
| f1g4 := int64(f1) * int64(g4) | |||
| f1g5_2 := int64(f1_2) * int64(g5) | |||
| f1g6 := int64(f1) * int64(g6) | |||
| f1g7_2 := int64(f1_2) * int64(g7) | |||
| f1g8 := int64(f1) * int64(g8) | |||
| f1g9_38 := int64(f1_2) * int64(g9_19) | |||
| f2g0 := int64(f2) * int64(g0) | |||
| f2g1 := int64(f2) * int64(g1) | |||
| f2g2 := int64(f2) * int64(g2) | |||
| f2g3 := int64(f2) * int64(g3) | |||
| f2g4 := int64(f2) * int64(g4) | |||
| f2g5 := int64(f2) * int64(g5) | |||
| f2g6 := int64(f2) * int64(g6) | |||
| f2g7 := int64(f2) * int64(g7) | |||
| f2g8_19 := int64(f2) * int64(g8_19) | |||
| f2g9_19 := int64(f2) * int64(g9_19) | |||
| f3g0 := int64(f3) * int64(g0) | |||
| f3g1_2 := int64(f3_2) * int64(g1) | |||
| f3g2 := int64(f3) * int64(g2) | |||
| f3g3_2 := int64(f3_2) * int64(g3) | |||
| f3g4 := int64(f3) * int64(g4) | |||
| f3g5_2 := int64(f3_2) * int64(g5) | |||
| f3g6 := int64(f3) * int64(g6) | |||
| f3g7_38 := int64(f3_2) * int64(g7_19) | |||
| f3g8_19 := int64(f3) * int64(g8_19) | |||
| f3g9_38 := int64(f3_2) * int64(g9_19) | |||
| f4g0 := int64(f4) * int64(g0) | |||
| f4g1 := int64(f4) * int64(g1) | |||
| f4g2 := int64(f4) * int64(g2) | |||
| f4g3 := int64(f4) * int64(g3) | |||
| f4g4 := int64(f4) * int64(g4) | |||
| f4g5 := int64(f4) * int64(g5) | |||
| f4g6_19 := int64(f4) * int64(g6_19) | |||
| f4g7_19 := int64(f4) * int64(g7_19) | |||
| f4g8_19 := int64(f4) * int64(g8_19) | |||
| f4g9_19 := int64(f4) * int64(g9_19) | |||
| f5g0 := int64(f5) * int64(g0) | |||
| f5g1_2 := int64(f5_2) * int64(g1) | |||
| f5g2 := int64(f5) * int64(g2) | |||
| f5g3_2 := int64(f5_2) * int64(g3) | |||
| f5g4 := int64(f5) * int64(g4) | |||
| f5g5_38 := int64(f5_2) * int64(g5_19) | |||
| f5g6_19 := int64(f5) * int64(g6_19) | |||
| f5g7_38 := int64(f5_2) * int64(g7_19) | |||
| f5g8_19 := int64(f5) * int64(g8_19) | |||
| f5g9_38 := int64(f5_2) * int64(g9_19) | |||
| f6g0 := int64(f6) * int64(g0) | |||
| f6g1 := int64(f6) * int64(g1) | |||
| f6g2 := int64(f6) * int64(g2) | |||
| f6g3 := int64(f6) * int64(g3) | |||
| f6g4_19 := int64(f6) * int64(g4_19) | |||
| f6g5_19 := int64(f6) * int64(g5_19) | |||
| f6g6_19 := int64(f6) * int64(g6_19) | |||
| f6g7_19 := int64(f6) * int64(g7_19) | |||
| f6g8_19 := int64(f6) * int64(g8_19) | |||
| f6g9_19 := int64(f6) * int64(g9_19) | |||
| f7g0 := int64(f7) * int64(g0) | |||
| f7g1_2 := int64(f7_2) * int64(g1) | |||
| f7g2 := int64(f7) * int64(g2) | |||
| f7g3_38 := int64(f7_2) * int64(g3_19) | |||
| f7g4_19 := int64(f7) * int64(g4_19) | |||
| f7g5_38 := int64(f7_2) * int64(g5_19) | |||
| f7g6_19 := int64(f7) * int64(g6_19) | |||
| f7g7_38 := int64(f7_2) * int64(g7_19) | |||
| f7g8_19 := int64(f7) * int64(g8_19) | |||
| f7g9_38 := int64(f7_2) * int64(g9_19) | |||
| f8g0 := int64(f8) * int64(g0) | |||
| f8g1 := int64(f8) * int64(g1) | |||
| f8g2_19 := int64(f8) * int64(g2_19) | |||
| f8g3_19 := int64(f8) * int64(g3_19) | |||
| f8g4_19 := int64(f8) * int64(g4_19) | |||
| f8g5_19 := int64(f8) * int64(g5_19) | |||
| f8g6_19 := int64(f8) * int64(g6_19) | |||
| f8g7_19 := int64(f8) * int64(g7_19) | |||
| f8g8_19 := int64(f8) * int64(g8_19) | |||
| f8g9_19 := int64(f8) * int64(g9_19) | |||
| f9g0 := int64(f9) * int64(g0) | |||
| f9g1_38 := int64(f9_2) * int64(g1_19) | |||
| f9g2_19 := int64(f9) * int64(g2_19) | |||
| f9g3_38 := int64(f9_2) * int64(g3_19) | |||
| f9g4_19 := int64(f9) * int64(g4_19) | |||
| f9g5_38 := int64(f9_2) * int64(g5_19) | |||
| f9g6_19 := int64(f9) * int64(g6_19) | |||
| f9g7_38 := int64(f9_2) * int64(g7_19) | |||
| f9g8_19 := int64(f9) * int64(g8_19) | |||
| f9g9_38 := int64(f9_2) * int64(g9_19) | |||
| h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38 | |||
| h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19 | |||
| h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38 | |||
| h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 | |||
| h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38 | |||
| h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 | |||
| h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38 | |||
| h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19 | |||
| h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38 | |||
| h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 | |||
| var carry [10]int64 | |||
| // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) | |||
| // i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 | |||
| // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) | |||
| // i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 | |||
| carry[0] = (h0 + (1 << 25)) >> 26 | |||
| h1 += carry[0] | |||
| h0 -= carry[0] << 26 | |||
| carry[4] = (h4 + (1 << 25)) >> 26 | |||
| h5 += carry[4] | |||
| h4 -= carry[4] << 26 | |||
| // |h0| <= 2^25 | |||
| // |h4| <= 2^25 | |||
| // |h1| <= 1.51*2^58 | |||
| // |h5| <= 1.51*2^58 | |||
| carry[1] = (h1 + (1 << 24)) >> 25 | |||
| h2 += carry[1] | |||
| h1 -= carry[1] << 25 | |||
| carry[5] = (h5 + (1 << 24)) >> 25 | |||
| h6 += carry[5] | |||
| h5 -= carry[5] << 25 | |||
| // |h1| <= 2^24; from now on fits into int32 | |||
| // |h5| <= 2^24; from now on fits into int32 | |||
| // |h2| <= 1.21*2^59 | |||
| // |h6| <= 1.21*2^59 | |||
| carry[2] = (h2 + (1 << 25)) >> 26 | |||
| h3 += carry[2] | |||
| h2 -= carry[2] << 26 | |||
| carry[6] = (h6 + (1 << 25)) >> 26 | |||
| h7 += carry[6] | |||
| h6 -= carry[6] << 26 | |||
| // |h2| <= 2^25; from now on fits into int32 unchanged | |||
| // |h6| <= 2^25; from now on fits into int32 unchanged | |||
| // |h3| <= 1.51*2^58 | |||
| // |h7| <= 1.51*2^58 | |||
| carry[3] = (h3 + (1 << 24)) >> 25 | |||
| h4 += carry[3] | |||
| h3 -= carry[3] << 25 | |||
| carry[7] = (h7 + (1 << 24)) >> 25 | |||
| h8 += carry[7] | |||
| h7 -= carry[7] << 25 | |||
| // |h3| <= 2^24; from now on fits into int32 unchanged | |||
| // |h7| <= 2^24; from now on fits into int32 unchanged | |||
| // |h4| <= 1.52*2^33 | |||
| // |h8| <= 1.52*2^33 | |||
| carry[4] = (h4 + (1 << 25)) >> 26 | |||
| h5 += carry[4] | |||
| h4 -= carry[4] << 26 | |||
| carry[8] = (h8 + (1 << 25)) >> 26 | |||
| h9 += carry[8] | |||
| h8 -= carry[8] << 26 | |||
| // |h4| <= 2^25; from now on fits into int32 unchanged | |||
| // |h8| <= 2^25; from now on fits into int32 unchanged | |||
| // |h5| <= 1.01*2^24 | |||
| // |h9| <= 1.51*2^58 | |||
| carry[9] = (h9 + (1 << 24)) >> 25 | |||
| h0 += carry[9] * 19 | |||
| h9 -= carry[9] << 25 | |||
| // |h9| <= 2^24; from now on fits into int32 unchanged | |||
| // |h0| <= 1.8*2^37 | |||
| carry[0] = (h0 + (1 << 25)) >> 26 | |||
| h1 += carry[0] | |||
| h0 -= carry[0] << 26 | |||
| // |h0| <= 2^25; from now on fits into int32 unchanged | |||
| // |h1| <= 1.01*2^24 | |||
| h[0] = int32(h0) | |||
| h[1] = int32(h1) | |||
| h[2] = int32(h2) | |||
| h[3] = int32(h3) | |||
| h[4] = int32(h4) | |||
| h[5] = int32(h5) | |||
| h[6] = int32(h6) | |||
| h[7] = int32(h7) | |||
| h[8] = int32(h8) | |||
| h[9] = int32(h9) | |||
| } | |||
| // feSquare calculates h = f*f. Can overlap h with f. | |||
| // | |||
| // Preconditions: | |||
| // |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | |||
| // | |||
| // Postconditions: | |||
| // |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | |||
| func feSquare(h, f *fieldElement) { | |||
| f0 := f[0] | |||
| f1 := f[1] | |||
| f2 := f[2] | |||
| f3 := f[3] | |||
| f4 := f[4] | |||
| f5 := f[5] | |||
| f6 := f[6] | |||
| f7 := f[7] | |||
| f8 := f[8] | |||
| f9 := f[9] | |||
| f0_2 := 2 * f0 | |||
| f1_2 := 2 * f1 | |||
| f2_2 := 2 * f2 | |||
| f3_2 := 2 * f3 | |||
| f4_2 := 2 * f4 | |||
| f5_2 := 2 * f5 | |||
| f6_2 := 2 * f6 | |||
| f7_2 := 2 * f7 | |||
| f5_38 := 38 * f5 // 1.31*2^30 | |||
| f6_19 := 19 * f6 // 1.31*2^30 | |||
| f7_38 := 38 * f7 // 1.31*2^30 | |||
| f8_19 := 19 * f8 // 1.31*2^30 | |||
| f9_38 := 38 * f9 // 1.31*2^30 | |||
| f0f0 := int64(f0) * int64(f0) | |||
| f0f1_2 := int64(f0_2) * int64(f1) | |||
| f0f2_2 := int64(f0_2) * int64(f2) | |||
| f0f3_2 := int64(f0_2) * int64(f3) | |||
| f0f4_2 := int64(f0_2) * int64(f4) | |||
| f0f5_2 := int64(f0_2) * int64(f5) | |||
| f0f6_2 := int64(f0_2) * int64(f6) | |||
| f0f7_2 := int64(f0_2) * int64(f7) | |||
| f0f8_2 := int64(f0_2) * int64(f8) | |||
| f0f9_2 := int64(f0_2) * int64(f9) | |||
| f1f1_2 := int64(f1_2) * int64(f1) | |||
| f1f2_2 := int64(f1_2) * int64(f2) | |||
| f1f3_4 := int64(f1_2) * int64(f3_2) | |||
| f1f4_2 := int64(f1_2) * int64(f4) | |||
| f1f5_4 := int64(f1_2) * int64(f5_2) | |||
| f1f6_2 := int64(f1_2) * int64(f6) | |||
| f1f7_4 := int64(f1_2) * int64(f7_2) | |||
| f1f8_2 := int64(f1_2) * int64(f8) | |||
| f1f9_76 := int64(f1_2) * int64(f9_38) | |||
| f2f2 := int64(f2) * int64(f2) | |||
| f2f3_2 := int64(f2_2) * int64(f3) | |||
| f2f4_2 := int64(f2_2) * int64(f4) | |||
| f2f5_2 := int64(f2_2) * int64(f5) | |||
| f2f6_2 := int64(f2_2) * int64(f6) | |||
| f2f7_2 := int64(f2_2) * int64(f7) | |||
| f2f8_38 := int64(f2_2) * int64(f8_19) | |||
| f2f9_38 := int64(f2) * int64(f9_38) | |||
| f3f3_2 := int64(f3_2) * int64(f3) | |||
| f3f4_2 := int64(f3_2) * int64(f4) | |||
| f3f5_4 := int64(f3_2) * int64(f5_2) | |||
| f3f6_2 := int64(f3_2) * int64(f6) | |||
| f3f7_76 := int64(f3_2) * int64(f7_38) | |||
| f3f8_38 := int64(f3_2) * int64(f8_19) | |||
| f3f9_76 := int64(f3_2) * int64(f9_38) | |||
| f4f4 := int64(f4) * int64(f4) | |||
| f4f5_2 := int64(f4_2) * int64(f5) | |||
| f4f6_38 := int64(f4_2) * int64(f6_19) | |||
| f4f7_38 := int64(f4) * int64(f7_38) | |||
| f4f8_38 := int64(f4_2) * int64(f8_19) | |||
| f4f9_38 := int64(f4) * int64(f9_38) | |||
| f5f5_38 := int64(f5) * int64(f5_38) | |||
| f5f6_38 := int64(f5_2) * int64(f6_19) | |||
| f5f7_76 := int64(f5_2) * int64(f7_38) | |||
| f5f8_38 := int64(f5_2) * int64(f8_19) | |||
| f5f9_76 := int64(f5_2) * int64(f9_38) | |||
| f6f6_19 := int64(f6) * int64(f6_19) | |||
| f6f7_38 := int64(f6) * int64(f7_38) | |||
| f6f8_38 := int64(f6_2) * int64(f8_19) | |||
| f6f9_38 := int64(f6) * int64(f9_38) | |||
| f7f7_38 := int64(f7) * int64(f7_38) | |||
| f7f8_38 := int64(f7_2) * int64(f8_19) | |||
| f7f9_76 := int64(f7_2) * int64(f9_38) | |||
| f8f8_19 := int64(f8) * int64(f8_19) | |||
| f8f9_38 := int64(f8) * int64(f9_38) | |||
| f9f9_38 := int64(f9) * int64(f9_38) | |||
| h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38 | |||
| h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38 | |||
| h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19 | |||
| h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38 | |||
| h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38 | |||
| h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38 | |||
| h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19 | |||
| h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38 | |||
| h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38 | |||
| h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 | |||
| var carry [10]int64 | |||
| carry[0] = (h0 + (1 << 25)) >> 26 | |||
| h1 += carry[0] | |||
| h0 -= carry[0] << 26 | |||
| carry[4] = (h4 + (1 << 25)) >> 26 | |||
| h5 += carry[4] | |||
| h4 -= carry[4] << 26 | |||
| carry[1] = (h1 + (1 << 24)) >> 25 | |||
| h2 += carry[1] | |||
| h1 -= carry[1] << 25 | |||
| carry[5] = (h5 + (1 << 24)) >> 25 | |||
| h6 += carry[5] | |||
| h5 -= carry[5] << 25 | |||
| carry[2] = (h2 + (1 << 25)) >> 26 | |||
| h3 += carry[2] | |||
| h2 -= carry[2] << 26 | |||
| carry[6] = (h6 + (1 << 25)) >> 26 | |||
| h7 += carry[6] | |||
| h6 -= carry[6] << 26 | |||
| carry[3] = (h3 + (1 << 24)) >> 25 | |||
| h4 += carry[3] | |||
| h3 -= carry[3] << 25 | |||
| carry[7] = (h7 + (1 << 24)) >> 25 | |||
| h8 += carry[7] | |||
| h7 -= carry[7] << 25 | |||
| carry[4] = (h4 + (1 << 25)) >> 26 | |||
| h5 += carry[4] | |||
| h4 -= carry[4] << 26 | |||
| carry[8] = (h8 + (1 << 25)) >> 26 | |||
| h9 += carry[8] | |||
| h8 -= carry[8] << 26 | |||
| carry[9] = (h9 + (1 << 24)) >> 25 | |||
| h0 += carry[9] * 19 | |||
| h9 -= carry[9] << 25 | |||
| carry[0] = (h0 + (1 << 25)) >> 26 | |||
| h1 += carry[0] | |||
| h0 -= carry[0] << 26 | |||
| h[0] = int32(h0) | |||
| h[1] = int32(h1) | |||
| h[2] = int32(h2) | |||
| h[3] = int32(h3) | |||
| h[4] = int32(h4) | |||
| h[5] = int32(h5) | |||
| h[6] = int32(h6) | |||
| h[7] = int32(h7) | |||
| h[8] = int32(h8) | |||
| h[9] = int32(h9) | |||
| } | |||
| // feMul121666 calculates h = f * 121666. Can overlap h with f. | |||
| // | |||
| // Preconditions: | |||
| // |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | |||
| // | |||
| // Postconditions: | |||
| // |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | |||
| func feMul121666(h, f *fieldElement) { | |||
| h0 := int64(f[0]) * 121666 | |||
| h1 := int64(f[1]) * 121666 | |||
| h2 := int64(f[2]) * 121666 | |||
| h3 := int64(f[3]) * 121666 | |||
| h4 := int64(f[4]) * 121666 | |||
| h5 := int64(f[5]) * 121666 | |||
| h6 := int64(f[6]) * 121666 | |||
| h7 := int64(f[7]) * 121666 | |||
| h8 := int64(f[8]) * 121666 | |||
| h9 := int64(f[9]) * 121666 | |||
| var carry [10]int64 | |||
| carry[9] = (h9 + (1 << 24)) >> 25 | |||
| h0 += carry[9] * 19 | |||
| h9 -= carry[9] << 25 | |||
| carry[1] = (h1 + (1 << 24)) >> 25 | |||
| h2 += carry[1] | |||
| h1 -= carry[1] << 25 | |||
| carry[3] = (h3 + (1 << 24)) >> 25 | |||
| h4 += carry[3] | |||
| h3 -= carry[3] << 25 | |||
| carry[5] = (h5 + (1 << 24)) >> 25 | |||
| h6 += carry[5] | |||
| h5 -= carry[5] << 25 | |||
| carry[7] = (h7 + (1 << 24)) >> 25 | |||
| h8 += carry[7] | |||
| h7 -= carry[7] << 25 | |||
| carry[0] = (h0 + (1 << 25)) >> 26 | |||
| h1 += carry[0] | |||
| h0 -= carry[0] << 26 | |||
| carry[2] = (h2 + (1 << 25)) >> 26 | |||
| h3 += carry[2] | |||
| h2 -= carry[2] << 26 | |||
| carry[4] = (h4 + (1 << 25)) >> 26 | |||
| h5 += carry[4] | |||
| h4 -= carry[4] << 26 | |||
| carry[6] = (h6 + (1 << 25)) >> 26 | |||
| h7 += carry[6] | |||
| h6 -= carry[6] << 26 | |||
| carry[8] = (h8 + (1 << 25)) >> 26 | |||
| h9 += carry[8] | |||
| h8 -= carry[8] << 26 | |||
| h[0] = int32(h0) | |||
| h[1] = int32(h1) | |||
| h[2] = int32(h2) | |||
| h[3] = int32(h3) | |||
| h[4] = int32(h4) | |||
| h[5] = int32(h5) | |||
| h[6] = int32(h6) | |||
| h[7] = int32(h7) | |||
| h[8] = int32(h8) | |||
| h[9] = int32(h9) | |||
| } | |||
| // feInvert sets out = z^-1. | |||
| func feInvert(out, z *fieldElement) { | |||
| var t0, t1, t2, t3 fieldElement | |||
| var i int | |||
| feSquare(&t0, z) | |||
| for i = 1; i < 1; i++ { | |||
| feSquare(&t0, &t0) | |||
| } | |||
| feSquare(&t1, &t0) | |||
| for i = 1; i < 2; i++ { | |||
| feSquare(&t1, &t1) | |||
| } | |||
| feMul(&t1, z, &t1) | |||
| feMul(&t0, &t0, &t1) | |||
| feSquare(&t2, &t0) | |||
| for i = 1; i < 1; i++ { | |||
| feSquare(&t2, &t2) | |||
| } | |||
| feMul(&t1, &t1, &t2) | |||
| feSquare(&t2, &t1) | |||
| for i = 1; i < 5; i++ { | |||
| feSquare(&t2, &t2) | |||
| } | |||
| feMul(&t1, &t2, &t1) | |||
| feSquare(&t2, &t1) | |||
| for i = 1; i < 10; i++ { | |||
| feSquare(&t2, &t2) | |||
| } | |||
| feMul(&t2, &t2, &t1) | |||
| feSquare(&t3, &t2) | |||
| for i = 1; i < 20; i++ { | |||
| feSquare(&t3, &t3) | |||
| } | |||
| feMul(&t2, &t3, &t2) | |||
| feSquare(&t2, &t2) | |||
| for i = 1; i < 10; i++ { | |||
| feSquare(&t2, &t2) | |||
| } | |||
| feMul(&t1, &t2, &t1) | |||
| feSquare(&t2, &t1) | |||
| for i = 1; i < 50; i++ { | |||
| feSquare(&t2, &t2) | |||
| } | |||
| feMul(&t2, &t2, &t1) | |||
| feSquare(&t3, &t2) | |||
| for i = 1; i < 100; i++ { | |||
| feSquare(&t3, &t3) | |||
| } | |||
| feMul(&t2, &t3, &t2) | |||
| feSquare(&t2, &t2) | |||
| for i = 1; i < 50; i++ { | |||
| feSquare(&t2, &t2) | |||
| } | |||
| feMul(&t1, &t2, &t1) | |||
| feSquare(&t1, &t1) | |||
| for i = 1; i < 5; i++ { | |||
| feSquare(&t1, &t1) | |||
| } | |||
| feMul(out, &t1, &t0) | |||
| } | |||
| func scalarMult(out, in, base *[32]byte) { | |||
| var e [32]byte | |||
| copy(e[:], in[:]) | |||
| e[0] &= 248 | |||
| e[31] &= 127 | |||
| e[31] |= 64 | |||
| var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement | |||
| feFromBytes(&x1, base) | |||
| feOne(&x2) | |||
| feCopy(&x3, &x1) | |||
| feOne(&z3) | |||
| swap := int32(0) | |||
| for pos := 254; pos >= 0; pos-- { | |||
| b := e[pos/8] >> uint(pos&7) | |||
| b &= 1 | |||
| swap ^= int32(b) | |||
| feCSwap(&x2, &x3, swap) | |||
| feCSwap(&z2, &z3, swap) | |||
| swap = int32(b) | |||
| feSub(&tmp0, &x3, &z3) | |||
| feSub(&tmp1, &x2, &z2) | |||
| feAdd(&x2, &x2, &z2) | |||
| feAdd(&z2, &x3, &z3) | |||
| feMul(&z3, &tmp0, &x2) | |||
| feMul(&z2, &z2, &tmp1) | |||
| feSquare(&tmp0, &tmp1) | |||
| feSquare(&tmp1, &x2) | |||
| feAdd(&x3, &z3, &z2) | |||
| feSub(&z2, &z3, &z2) | |||
| feMul(&x2, &tmp1, &tmp0) | |||
| feSub(&tmp1, &tmp1, &tmp0) | |||
| feSquare(&z2, &z2) | |||
| feMul121666(&z3, &tmp1) | |||
| feSquare(&x3, &x3) | |||
| feAdd(&tmp0, &tmp0, &z3) | |||
| feMul(&z3, &x1, &z2) | |||
| feMul(&z2, &tmp1, &tmp0) | |||
| } | |||
| feCSwap(&x2, &x3, swap) | |||
| feCSwap(&z2, &z3, swap) | |||
| feInvert(&z2, &z2) | |||
| feMul(&x2, &x2, &z2) | |||
| feToBytes(out, &x2) | |||
| } | |||
| @@ -0,0 +1,113 @@ | |||
| package curve25519 | |||
| import ( | |||
| "crypto/elliptic" | |||
| "math/big" | |||
| "sync" | |||
| ) | |||
| var cv25519 cv25519Curve | |||
| type cv25519Curve struct { | |||
| *elliptic.CurveParams | |||
| } | |||
| func copyReverse(dst []byte, src []byte) { | |||
| // Curve 25519 multiplication functions expect scalars in reverse | |||
| // order than PGP. To keep the curve25519Curve type consistent | |||
| // with other curves, we reverse it here. | |||
| for i, j := 0, len(src)-1; j >= 0; i, j = i+1, j-1 { | |||
| dst[i] = src[j] | |||
| } | |||
| } | |||
| func (cv25519Curve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) { | |||
| // Assume y1 is 0 with cv25519. | |||
| var dst [32]byte | |||
| var x1Bytes [32]byte | |||
| var scalarBytes [32]byte | |||
| copy(x1Bytes[:], x1.Bytes()[:32]) | |||
| copyReverse(scalarBytes[:], scalar[:32]) | |||
| scalarMult(&dst, &scalarBytes, &x1Bytes) | |||
| x = new(big.Int).SetBytes(dst[:]) | |||
| y = new(big.Int) | |||
| return x, y | |||
| } | |||
| func (cv25519Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) { | |||
| var dst [32]byte | |||
| var scalarBytes [32]byte | |||
| copyReverse(scalarBytes[:], scalar[:32]) | |||
| scalarMult(&dst, &scalarBytes, &basePoint) | |||
| x = new(big.Int).SetBytes(dst[:]) | |||
| y = new(big.Int) | |||
| return x, y | |||
| } | |||
| func (cv25519Curve) IsOnCurve(bigX, bigY *big.Int) bool { | |||
| return bigY.Sign() == 0 // bigY == 0 ? | |||
| } | |||
| // More information about 0x40 point format: | |||
| // https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-00#section-3 | |||
| // In addition to uncompressed point format described here: | |||
| // https://tools.ietf.org/html/rfc6637#section-6 | |||
| func (cv25519Curve) MarshalType40(x, y *big.Int) []byte { | |||
| byteLen := 32 | |||
| ret := make([]byte, 1+byteLen) | |||
| ret[0] = 0x40 | |||
| xBytes := x.Bytes() | |||
| copy(ret[1+byteLen-len(xBytes):], xBytes) | |||
| return ret | |||
| } | |||
| func (cv25519Curve) UnmarshalType40(data []byte) (x, y *big.Int) { | |||
| if len(data) != 1+32 { | |||
| return nil, nil | |||
| } | |||
| if data[0] != 0x40 { | |||
| return nil, nil | |||
| } | |||
| x = new(big.Int).SetBytes(data[1:]) | |||
| // Any x is a valid curve point. | |||
| return x, new(big.Int) | |||
| } | |||
| // ToCurve25519 casts given elliptic.Curve type to Curve25519 type, or | |||
| // returns nil, false if cast was unsuccessful. | |||
| func ToCurve25519(cv elliptic.Curve) (cv25519Curve, bool) { | |||
| cv2, ok := cv.(cv25519Curve) | |||
| return cv2, ok | |||
| } | |||
| func initCv25519() { | |||
| cv25519.CurveParams = &elliptic.CurveParams{Name: "Curve 25519"} | |||
| // Some code relies on these parameters being available for | |||
| // checking Curve coordinate length. They should not be used | |||
| // directly for any calculations. | |||
| cv25519.P, _ = new (big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16) | |||
| cv25519.N, _ = new (big.Int).SetString("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16) | |||
| cv25519.Gx, _ = new (big.Int).SetString("9", 16) | |||
| cv25519.Gy, _ = new (big.Int).SetString("20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9", 16) | |||
| cv25519.BitSize = 256 | |||
| } | |||
| var initonce sync.Once | |||
| // Cv25519 returns a Curve which (partially) implements Cv25519. Only | |||
| // ScalarMult and ScalarBaseMult are valid for this curve. Add and | |||
| // Double should not be used. | |||
| func Cv25519() elliptic.Curve { | |||
| initonce.Do(initCv25519) | |||
| return cv25519 | |||
| } | |||
| func (curve cv25519Curve) Params() *elliptic.CurveParams { | |||
| return curve.CurveParams | |||
| } | |||
| @@ -0,0 +1,23 @@ | |||
| // Copyright 2012 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // Package curve25519 provides an implementation of scalar multiplication on | |||
| // the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html | |||
| package curve25519 | |||
| // basePoint is the x coordinate of the generator of the curve. | |||
| var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} | |||
| // ScalarMult sets dst to the product in*base where dst and base are the x | |||
| // coordinates of group points and all values are in little-endian form. | |||
| func ScalarMult(dst, in, base *[32]byte) { | |||
| scalarMult(dst, in, base) | |||
| } | |||
| // ScalarBaseMult sets dst to the product in*base where dst and base are the x | |||
| // coordinates of group points, base is the standard generator and all values | |||
| // are in little-endian form. | |||
| func ScalarBaseMult(dst, in *[32]byte) { | |||
| ScalarMult(dst, in, &basePoint) | |||
| } | |||
| @@ -0,0 +1,94 @@ | |||
| // Copyright 2012 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // This code was translated into a form compatible with 6a from the public | |||
| // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||
| // +build amd64,!gccgo,!appengine | |||
| // func freeze(inout *[5]uint64) | |||
| TEXT ·freeze(SB),7,$96-8 | |||
| MOVQ inout+0(FP), DI | |||
| MOVQ SP,R11 | |||
| MOVQ $31,CX | |||
| NOTQ CX | |||
| ANDQ CX,SP | |||
| ADDQ $32,SP | |||
| MOVQ R11,0(SP) | |||
| MOVQ R12,8(SP) | |||
| MOVQ R13,16(SP) | |||
| MOVQ R14,24(SP) | |||
| MOVQ R15,32(SP) | |||
| MOVQ BX,40(SP) | |||
| MOVQ BP,48(SP) | |||
| MOVQ 0(DI),SI | |||
| MOVQ 8(DI),DX | |||
| MOVQ 16(DI),CX | |||
| MOVQ 24(DI),R8 | |||
| MOVQ 32(DI),R9 | |||
| MOVQ ·REDMASK51(SB),AX | |||
| MOVQ AX,R10 | |||
| SUBQ $18,R10 | |||
| MOVQ $3,R11 | |||
| REDUCELOOP: | |||
| MOVQ SI,R12 | |||
| SHRQ $51,R12 | |||
| ANDQ AX,SI | |||
| ADDQ R12,DX | |||
| MOVQ DX,R12 | |||
| SHRQ $51,R12 | |||
| ANDQ AX,DX | |||
| ADDQ R12,CX | |||
| MOVQ CX,R12 | |||
| SHRQ $51,R12 | |||
| ANDQ AX,CX | |||
| ADDQ R12,R8 | |||
| MOVQ R8,R12 | |||
| SHRQ $51,R12 | |||
| ANDQ AX,R8 | |||
| ADDQ R12,R9 | |||
| MOVQ R9,R12 | |||
| SHRQ $51,R12 | |||
| ANDQ AX,R9 | |||
| IMUL3Q $19,R12,R12 | |||
| ADDQ R12,SI | |||
| SUBQ $1,R11 | |||
| JA REDUCELOOP | |||
| MOVQ $1,R12 | |||
| CMPQ R10,SI | |||
| CMOVQLT R11,R12 | |||
| CMPQ AX,DX | |||
| CMOVQNE R11,R12 | |||
| CMPQ AX,CX | |||
| CMOVQNE R11,R12 | |||
| CMPQ AX,R8 | |||
| CMOVQNE R11,R12 | |||
| CMPQ AX,R9 | |||
| CMOVQNE R11,R12 | |||
| NEGQ R12 | |||
| ANDQ R12,AX | |||
| ANDQ R12,R10 | |||
| SUBQ R10,SI | |||
| SUBQ AX,DX | |||
| SUBQ AX,CX | |||
| SUBQ AX,R8 | |||
| SUBQ AX,R9 | |||
| MOVQ SI,0(DI) | |||
| MOVQ DX,8(DI) | |||
| MOVQ CX,16(DI) | |||
| MOVQ R8,24(DI) | |||
| MOVQ R9,32(DI) | |||
| MOVQ 0(SP),R11 | |||
| MOVQ 8(SP),R12 | |||
| MOVQ 16(SP),R13 | |||
| MOVQ 24(SP),R14 | |||
| MOVQ 32(SP),R15 | |||
| MOVQ 40(SP),BX | |||
| MOVQ 48(SP),BP | |||
| MOVQ R11,SP | |||
| MOVQ DI,AX | |||
| MOVQ SI,DX | |||
| RET | |||
| @@ -0,0 +1,240 @@ | |||
| // Copyright 2012 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build amd64,!gccgo,!appengine | |||
| package curve25519 | |||
| // These functions are implemented in the .s files. The names of the functions | |||
| // in the rest of the file are also taken from the SUPERCOP sources to help | |||
| // people following along. | |||
| //go:noescape | |||
| func cswap(inout *[5]uint64, v uint64) | |||
| //go:noescape | |||
| func ladderstep(inout *[5][5]uint64) | |||
| //go:noescape | |||
| func freeze(inout *[5]uint64) | |||
| //go:noescape | |||
| func mul(dest, a, b *[5]uint64) | |||
| //go:noescape | |||
| func square(out, in *[5]uint64) | |||
| // mladder uses a Montgomery ladder to calculate (xr/zr) *= s. | |||
| func mladder(xr, zr *[5]uint64, s *[32]byte) { | |||
| var work [5][5]uint64 | |||
| work[0] = *xr | |||
| setint(&work[1], 1) | |||
| setint(&work[2], 0) | |||
| work[3] = *xr | |||
| setint(&work[4], 1) | |||
| j := uint(6) | |||
| var prevbit byte | |||
| for i := 31; i >= 0; i-- { | |||
| for j < 8 { | |||
| bit := ((*s)[i] >> j) & 1 | |||
| swap := bit ^ prevbit | |||
| prevbit = bit | |||
| cswap(&work[1], uint64(swap)) | |||
| ladderstep(&work) | |||
| j-- | |||
| } | |||
| j = 7 | |||
| } | |||
| *xr = work[1] | |||
| *zr = work[2] | |||
| } | |||
| func scalarMult(out, in, base *[32]byte) { | |||
| var e [32]byte | |||
| copy(e[:], (*in)[:]) | |||
| e[0] &= 248 | |||
| e[31] &= 127 | |||
| e[31] |= 64 | |||
| var t, z [5]uint64 | |||
| unpack(&t, base) | |||
| mladder(&t, &z, &e) | |||
| invert(&z, &z) | |||
| mul(&t, &t, &z) | |||
| pack(out, &t) | |||
| } | |||
| func setint(r *[5]uint64, v uint64) { | |||
| r[0] = v | |||
| r[1] = 0 | |||
| r[2] = 0 | |||
| r[3] = 0 | |||
| r[4] = 0 | |||
| } | |||
| // unpack sets r = x where r consists of 5, 51-bit limbs in little-endian | |||
| // order. | |||
| func unpack(r *[5]uint64, x *[32]byte) { | |||
| r[0] = uint64(x[0]) | | |||
| uint64(x[1])<<8 | | |||
| uint64(x[2])<<16 | | |||
| uint64(x[3])<<24 | | |||
| uint64(x[4])<<32 | | |||
| uint64(x[5])<<40 | | |||
| uint64(x[6]&7)<<48 | |||
| r[1] = uint64(x[6])>>3 | | |||
| uint64(x[7])<<5 | | |||
| uint64(x[8])<<13 | | |||
| uint64(x[9])<<21 | | |||
| uint64(x[10])<<29 | | |||
| uint64(x[11])<<37 | | |||
| uint64(x[12]&63)<<45 | |||
| r[2] = uint64(x[12])>>6 | | |||
| uint64(x[13])<<2 | | |||
| uint64(x[14])<<10 | | |||
| uint64(x[15])<<18 | | |||
| uint64(x[16])<<26 | | |||
| uint64(x[17])<<34 | | |||
| uint64(x[18])<<42 | | |||
| uint64(x[19]&1)<<50 | |||
| r[3] = uint64(x[19])>>1 | | |||
| uint64(x[20])<<7 | | |||
| uint64(x[21])<<15 | | |||
| uint64(x[22])<<23 | | |||
| uint64(x[23])<<31 | | |||
| uint64(x[24])<<39 | | |||
| uint64(x[25]&15)<<47 | |||
| r[4] = uint64(x[25])>>4 | | |||
| uint64(x[26])<<4 | | |||
| uint64(x[27])<<12 | | |||
| uint64(x[28])<<20 | | |||
| uint64(x[29])<<28 | | |||
| uint64(x[30])<<36 | | |||
| uint64(x[31]&127)<<44 | |||
| } | |||
| // pack sets out = x where out is the usual, little-endian form of the 5, | |||
| // 51-bit limbs in x. | |||
| func pack(out *[32]byte, x *[5]uint64) { | |||
| t := *x | |||
| freeze(&t) | |||
| out[0] = byte(t[0]) | |||
| out[1] = byte(t[0] >> 8) | |||
| out[2] = byte(t[0] >> 16) | |||
| out[3] = byte(t[0] >> 24) | |||
| out[4] = byte(t[0] >> 32) | |||
| out[5] = byte(t[0] >> 40) | |||
| out[6] = byte(t[0] >> 48) | |||
| out[6] ^= byte(t[1]<<3) & 0xf8 | |||
| out[7] = byte(t[1] >> 5) | |||
| out[8] = byte(t[1] >> 13) | |||
| out[9] = byte(t[1] >> 21) | |||
| out[10] = byte(t[1] >> 29) | |||
| out[11] = byte(t[1] >> 37) | |||
| out[12] = byte(t[1] >> 45) | |||
| out[12] ^= byte(t[2]<<6) & 0xc0 | |||
| out[13] = byte(t[2] >> 2) | |||
| out[14] = byte(t[2] >> 10) | |||
| out[15] = byte(t[2] >> 18) | |||
| out[16] = byte(t[2] >> 26) | |||
| out[17] = byte(t[2] >> 34) | |||
| out[18] = byte(t[2] >> 42) | |||
| out[19] = byte(t[2] >> 50) | |||
| out[19] ^= byte(t[3]<<1) & 0xfe | |||
| out[20] = byte(t[3] >> 7) | |||
| out[21] = byte(t[3] >> 15) | |||
| out[22] = byte(t[3] >> 23) | |||
| out[23] = byte(t[3] >> 31) | |||
| out[24] = byte(t[3] >> 39) | |||
| out[25] = byte(t[3] >> 47) | |||
| out[25] ^= byte(t[4]<<4) & 0xf0 | |||
| out[26] = byte(t[4] >> 4) | |||
| out[27] = byte(t[4] >> 12) | |||
| out[28] = byte(t[4] >> 20) | |||
| out[29] = byte(t[4] >> 28) | |||
| out[30] = byte(t[4] >> 36) | |||
| out[31] = byte(t[4] >> 44) | |||
| } | |||
| // invert calculates r = x^-1 mod p using Fermat's little theorem. | |||
| func invert(r *[5]uint64, x *[5]uint64) { | |||
| var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64 | |||
| square(&z2, x) /* 2 */ | |||
| square(&t, &z2) /* 4 */ | |||
| square(&t, &t) /* 8 */ | |||
| mul(&z9, &t, x) /* 9 */ | |||
| mul(&z11, &z9, &z2) /* 11 */ | |||
| square(&t, &z11) /* 22 */ | |||
| mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */ | |||
| square(&t, &z2_5_0) /* 2^6 - 2^1 */ | |||
| for i := 1; i < 5; i++ { /* 2^20 - 2^10 */ | |||
| square(&t, &t) | |||
| } | |||
| mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */ | |||
| square(&t, &z2_10_0) /* 2^11 - 2^1 */ | |||
| for i := 1; i < 10; i++ { /* 2^20 - 2^10 */ | |||
| square(&t, &t) | |||
| } | |||
| mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */ | |||
| square(&t, &z2_20_0) /* 2^21 - 2^1 */ | |||
| for i := 1; i < 20; i++ { /* 2^40 - 2^20 */ | |||
| square(&t, &t) | |||
| } | |||
| mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */ | |||
| square(&t, &t) /* 2^41 - 2^1 */ | |||
| for i := 1; i < 10; i++ { /* 2^50 - 2^10 */ | |||
| square(&t, &t) | |||
| } | |||
| mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */ | |||
| square(&t, &z2_50_0) /* 2^51 - 2^1 */ | |||
| for i := 1; i < 50; i++ { /* 2^100 - 2^50 */ | |||
| square(&t, &t) | |||
| } | |||
| mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */ | |||
| square(&t, &z2_100_0) /* 2^101 - 2^1 */ | |||
| for i := 1; i < 100; i++ { /* 2^200 - 2^100 */ | |||
| square(&t, &t) | |||
| } | |||
| mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */ | |||
| square(&t, &t) /* 2^201 - 2^1 */ | |||
| for i := 1; i < 50; i++ { /* 2^250 - 2^50 */ | |||
| square(&t, &t) | |||
| } | |||
| mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */ | |||
| square(&t, &t) /* 2^251 - 2^1 */ | |||
| square(&t, &t) /* 2^252 - 2^2 */ | |||
| square(&t, &t) /* 2^253 - 2^3 */ | |||
| square(&t, &t) /* 2^254 - 2^4 */ | |||
| square(&t, &t) /* 2^255 - 2^5 */ | |||
| mul(r, &t, &z11) /* 2^255 - 21 */ | |||
| } | |||
| @@ -0,0 +1,191 @@ | |||
| // Copyright 2012 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // This code was translated into a form compatible with 6a from the public | |||
| // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||
| // +build amd64,!gccgo,!appengine | |||
| // func mul(dest, a, b *[5]uint64) | |||
| TEXT ·mul(SB),0,$128-24 | |||
| MOVQ dest+0(FP), DI | |||
| MOVQ a+8(FP), SI | |||
| MOVQ b+16(FP), DX | |||
| MOVQ SP,R11 | |||
| MOVQ $31,CX | |||
| NOTQ CX | |||
| ANDQ CX,SP | |||
| ADDQ $32,SP | |||
| MOVQ R11,0(SP) | |||
| MOVQ R12,8(SP) | |||
| MOVQ R13,16(SP) | |||
| MOVQ R14,24(SP) | |||
| MOVQ R15,32(SP) | |||
| MOVQ BX,40(SP) | |||
| MOVQ BP,48(SP) | |||
| MOVQ DI,56(SP) | |||
| MOVQ DX,CX | |||
| MOVQ 24(SI),DX | |||
| IMUL3Q $19,DX,AX | |||
| MOVQ AX,64(SP) | |||
| MULQ 16(CX) | |||
| MOVQ AX,R8 | |||
| MOVQ DX,R9 | |||
| MOVQ 32(SI),DX | |||
| IMUL3Q $19,DX,AX | |||
| MOVQ AX,72(SP) | |||
| MULQ 8(CX) | |||
| ADDQ AX,R8 | |||
| ADCQ DX,R9 | |||
| MOVQ 0(SI),AX | |||
| MULQ 0(CX) | |||
| ADDQ AX,R8 | |||
| ADCQ DX,R9 | |||
| MOVQ 0(SI),AX | |||
| MULQ 8(CX) | |||
| MOVQ AX,R10 | |||
| MOVQ DX,R11 | |||
| MOVQ 0(SI),AX | |||
| MULQ 16(CX) | |||
| MOVQ AX,R12 | |||
| MOVQ DX,R13 | |||
| MOVQ 0(SI),AX | |||
| MULQ 24(CX) | |||
| MOVQ AX,R14 | |||
| MOVQ DX,R15 | |||
| MOVQ 0(SI),AX | |||
| MULQ 32(CX) | |||
| MOVQ AX,BX | |||
| MOVQ DX,BP | |||
| MOVQ 8(SI),AX | |||
| MULQ 0(CX) | |||
| ADDQ AX,R10 | |||
| ADCQ DX,R11 | |||
| MOVQ 8(SI),AX | |||
| MULQ 8(CX) | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ 8(SI),AX | |||
| MULQ 16(CX) | |||
| ADDQ AX,R14 | |||
| ADCQ DX,R15 | |||
| MOVQ 8(SI),AX | |||
| MULQ 24(CX) | |||
| ADDQ AX,BX | |||
| ADCQ DX,BP | |||
| MOVQ 8(SI),DX | |||
| IMUL3Q $19,DX,AX | |||
| MULQ 32(CX) | |||
| ADDQ AX,R8 | |||
| ADCQ DX,R9 | |||
| MOVQ 16(SI),AX | |||
| MULQ 0(CX) | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ 16(SI),AX | |||
| MULQ 8(CX) | |||
| ADDQ AX,R14 | |||
| ADCQ DX,R15 | |||
| MOVQ 16(SI),AX | |||
| MULQ 16(CX) | |||
| ADDQ AX,BX | |||
| ADCQ DX,BP | |||
| MOVQ 16(SI),DX | |||
| IMUL3Q $19,DX,AX | |||
| MULQ 24(CX) | |||
| ADDQ AX,R8 | |||
| ADCQ DX,R9 | |||
| MOVQ 16(SI),DX | |||
| IMUL3Q $19,DX,AX | |||
| MULQ 32(CX) | |||
| ADDQ AX,R10 | |||
| ADCQ DX,R11 | |||
| MOVQ 24(SI),AX | |||
| MULQ 0(CX) | |||
| ADDQ AX,R14 | |||
| ADCQ DX,R15 | |||
| MOVQ 24(SI),AX | |||
| MULQ 8(CX) | |||
| ADDQ AX,BX | |||
| ADCQ DX,BP | |||
| MOVQ 64(SP),AX | |||
| MULQ 24(CX) | |||
| ADDQ AX,R10 | |||
| ADCQ DX,R11 | |||
| MOVQ 64(SP),AX | |||
| MULQ 32(CX) | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ 32(SI),AX | |||
| MULQ 0(CX) | |||
| ADDQ AX,BX | |||
| ADCQ DX,BP | |||
| MOVQ 72(SP),AX | |||
| MULQ 16(CX) | |||
| ADDQ AX,R10 | |||
| ADCQ DX,R11 | |||
| MOVQ 72(SP),AX | |||
| MULQ 24(CX) | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ 72(SP),AX | |||
| MULQ 32(CX) | |||
| ADDQ AX,R14 | |||
| ADCQ DX,R15 | |||
| MOVQ ·REDMASK51(SB),SI | |||
| SHLQ $13,R9:R8 | |||
| ANDQ SI,R8 | |||
| SHLQ $13,R11:R10 | |||
| ANDQ SI,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| ANDQ SI,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| ANDQ SI,R14 | |||
| ADDQ R13,R14 | |||
| SHLQ $13,BP:BX | |||
| ANDQ SI,BX | |||
| ADDQ R15,BX | |||
| IMUL3Q $19,BP,DX | |||
| ADDQ DX,R8 | |||
| MOVQ R8,DX | |||
| SHRQ $51,DX | |||
| ADDQ R10,DX | |||
| MOVQ DX,CX | |||
| SHRQ $51,DX | |||
| ANDQ SI,R8 | |||
| ADDQ R12,DX | |||
| MOVQ DX,R9 | |||
| SHRQ $51,DX | |||
| ANDQ SI,CX | |||
| ADDQ R14,DX | |||
| MOVQ DX,AX | |||
| SHRQ $51,DX | |||
| ANDQ SI,R9 | |||
| ADDQ BX,DX | |||
| MOVQ DX,R10 | |||
| SHRQ $51,DX | |||
| ANDQ SI,AX | |||
| IMUL3Q $19,DX,DX | |||
| ADDQ DX,R8 | |||
| ANDQ SI,R10 | |||
| MOVQ R8,0(DI) | |||
| MOVQ CX,8(DI) | |||
| MOVQ R9,16(DI) | |||
| MOVQ AX,24(DI) | |||
| MOVQ R10,32(DI) | |||
| MOVQ 0(SP),R11 | |||
| MOVQ 8(SP),R12 | |||
| MOVQ 16(SP),R13 | |||
| MOVQ 24(SP),R14 | |||
| MOVQ 32(SP),R15 | |||
| MOVQ 40(SP),BX | |||
| MOVQ 48(SP),BP | |||
| MOVQ R11,SP | |||
| MOVQ DI,AX | |||
| MOVQ SI,DX | |||
| RET | |||
| @@ -0,0 +1,153 @@ | |||
| // Copyright 2012 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // This code was translated into a form compatible with 6a from the public | |||
| // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||
| // +build amd64,!gccgo,!appengine | |||
| // func square(out, in *[5]uint64) | |||
| TEXT ·square(SB),7,$96-16 | |||
| MOVQ out+0(FP), DI | |||
| MOVQ in+8(FP), SI | |||
| MOVQ SP,R11 | |||
| MOVQ $31,CX | |||
| NOTQ CX | |||
| ANDQ CX,SP | |||
| ADDQ $32, SP | |||
| MOVQ R11,0(SP) | |||
| MOVQ R12,8(SP) | |||
| MOVQ R13,16(SP) | |||
| MOVQ R14,24(SP) | |||
| MOVQ R15,32(SP) | |||
| MOVQ BX,40(SP) | |||
| MOVQ BP,48(SP) | |||
| MOVQ 0(SI),AX | |||
| MULQ 0(SI) | |||
| MOVQ AX,CX | |||
| MOVQ DX,R8 | |||
| MOVQ 0(SI),AX | |||
| SHLQ $1,AX | |||
| MULQ 8(SI) | |||
| MOVQ AX,R9 | |||
| MOVQ DX,R10 | |||
| MOVQ 0(SI),AX | |||
| SHLQ $1,AX | |||
| MULQ 16(SI) | |||
| MOVQ AX,R11 | |||
| MOVQ DX,R12 | |||
| MOVQ 0(SI),AX | |||
| SHLQ $1,AX | |||
| MULQ 24(SI) | |||
| MOVQ AX,R13 | |||
| MOVQ DX,R14 | |||
| MOVQ 0(SI),AX | |||
| SHLQ $1,AX | |||
| MULQ 32(SI) | |||
| MOVQ AX,R15 | |||
| MOVQ DX,BX | |||
| MOVQ 8(SI),AX | |||
| MULQ 8(SI) | |||
| ADDQ AX,R11 | |||
| ADCQ DX,R12 | |||
| MOVQ 8(SI),AX | |||
| SHLQ $1,AX | |||
| MULQ 16(SI) | |||
| ADDQ AX,R13 | |||
| ADCQ DX,R14 | |||
| MOVQ 8(SI),AX | |||
| SHLQ $1,AX | |||
| MULQ 24(SI) | |||
| ADDQ AX,R15 | |||
| ADCQ DX,BX | |||
| MOVQ 8(SI),DX | |||
| IMUL3Q $38,DX,AX | |||
| MULQ 32(SI) | |||
| ADDQ AX,CX | |||
| ADCQ DX,R8 | |||
| MOVQ 16(SI),AX | |||
| MULQ 16(SI) | |||
| ADDQ AX,R15 | |||
| ADCQ DX,BX | |||
| MOVQ 16(SI),DX | |||
| IMUL3Q $38,DX,AX | |||
| MULQ 24(SI) | |||
| ADDQ AX,CX | |||
| ADCQ DX,R8 | |||
| MOVQ 16(SI),DX | |||
| IMUL3Q $38,DX,AX | |||
| MULQ 32(SI) | |||
| ADDQ AX,R9 | |||
| ADCQ DX,R10 | |||
| MOVQ 24(SI),DX | |||
| IMUL3Q $19,DX,AX | |||
| MULQ 24(SI) | |||
| ADDQ AX,R9 | |||
| ADCQ DX,R10 | |||
| MOVQ 24(SI),DX | |||
| IMUL3Q $38,DX,AX | |||
| MULQ 32(SI) | |||
| ADDQ AX,R11 | |||
| ADCQ DX,R12 | |||
| MOVQ 32(SI),DX | |||
| IMUL3Q $19,DX,AX | |||
| MULQ 32(SI) | |||
| ADDQ AX,R13 | |||
| ADCQ DX,R14 | |||
| MOVQ ·REDMASK51(SB),SI | |||
| SHLQ $13,R8:CX | |||
| ANDQ SI,CX | |||
| SHLQ $13,R10:R9 | |||
| ANDQ SI,R9 | |||
| ADDQ R8,R9 | |||
| SHLQ $13,R12:R11 | |||
| ANDQ SI,R11 | |||
| ADDQ R10,R11 | |||
| SHLQ $13,R14:R13 | |||
| ANDQ SI,R13 | |||
| ADDQ R12,R13 | |||
| SHLQ $13,BX:R15 | |||
| ANDQ SI,R15 | |||
| ADDQ R14,R15 | |||
| IMUL3Q $19,BX,DX | |||
| ADDQ DX,CX | |||
| MOVQ CX,DX | |||
| SHRQ $51,DX | |||
| ADDQ R9,DX | |||
| ANDQ SI,CX | |||
| MOVQ DX,R8 | |||
| SHRQ $51,DX | |||
| ADDQ R11,DX | |||
| ANDQ SI,R8 | |||
| MOVQ DX,R9 | |||
| SHRQ $51,DX | |||
| ADDQ R13,DX | |||
| ANDQ SI,R9 | |||
| MOVQ DX,AX | |||
| SHRQ $51,DX | |||
| ADDQ R15,DX | |||
| ANDQ SI,AX | |||
| MOVQ DX,R10 | |||
| SHRQ $51,DX | |||
| IMUL3Q $19,DX,DX | |||
| ADDQ DX,CX | |||
| ANDQ SI,R10 | |||
| MOVQ CX,0(DI) | |||
| MOVQ R8,8(DI) | |||
| MOVQ R9,16(DI) | |||
| MOVQ AX,24(DI) | |||
| MOVQ R10,32(DI) | |||
| MOVQ 0(SP),R11 | |||
| MOVQ 8(SP),R12 | |||
| MOVQ 16(SP),R13 | |||
| MOVQ 24(SP),R14 | |||
| MOVQ 32(SP),R15 | |||
| MOVQ 40(SP),BX | |||
| MOVQ 48(SP),BP | |||
| MOVQ R11,SP | |||
| MOVQ DI,AX | |||
| MOVQ SI,DX | |||
| RET | |||
| @@ -0,0 +1,181 @@ | |||
| // Copyright 2016 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // Package ed25519 implements the Ed25519 signature algorithm. See | |||
| // http://ed25519.cr.yp.to/. | |||
| // | |||
| // These functions are also compatible with the “Ed25519” function defined in | |||
| // https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05. | |||
| package ed25519 | |||
| // This code is a port of the public domain, “ref10” implementation of ed25519 | |||
| // from SUPERCOP. | |||
| import ( | |||
| "crypto" | |||
| cryptorand "crypto/rand" | |||
| "crypto/sha512" | |||
| "crypto/subtle" | |||
| "errors" | |||
| "io" | |||
| "strconv" | |||
| "github.com/keybase/go-crypto/ed25519/internal/edwards25519" | |||
| ) | |||
| const ( | |||
| // PublicKeySize is the size, in bytes, of public keys as used in this package. | |||
| PublicKeySize = 32 | |||
| // PrivateKeySize is the size, in bytes, of private keys as used in this package. | |||
| PrivateKeySize = 64 | |||
| // SignatureSize is the size, in bytes, of signatures generated and verified by this package. | |||
| SignatureSize = 64 | |||
| ) | |||
| // PublicKey is the type of Ed25519 public keys. | |||
| type PublicKey []byte | |||
| // PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. | |||
| type PrivateKey []byte | |||
| // Public returns the PublicKey corresponding to priv. | |||
| func (priv PrivateKey) Public() crypto.PublicKey { | |||
| publicKey := make([]byte, PublicKeySize) | |||
| copy(publicKey, priv[32:]) | |||
| return PublicKey(publicKey) | |||
| } | |||
| // Sign signs the given message with priv. | |||
| // Ed25519 performs two passes over messages to be signed and therefore cannot | |||
| // handle pre-hashed messages. Thus opts.HashFunc() must return zero to | |||
| // indicate the message hasn't been hashed. This can be achieved by passing | |||
| // crypto.Hash(0) as the value for opts. | |||
| func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { | |||
| if opts.HashFunc() != crypto.Hash(0) { | |||
| return nil, errors.New("ed25519: cannot sign hashed message") | |||
| } | |||
| return Sign(priv, message), nil | |||
| } | |||
| // GenerateKey generates a public/private key pair using entropy from rand. | |||
| // If rand is nil, crypto/rand.Reader will be used. | |||
| func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) { | |||
| if rand == nil { | |||
| rand = cryptorand.Reader | |||
| } | |||
| privateKey = make([]byte, PrivateKeySize) | |||
| publicKey = make([]byte, PublicKeySize) | |||
| _, err = io.ReadFull(rand, privateKey[:32]) | |||
| if err != nil { | |||
| return nil, nil, err | |||
| } | |||
| digest := sha512.Sum512(privateKey[:32]) | |||
| digest[0] &= 248 | |||
| digest[31] &= 127 | |||
| digest[31] |= 64 | |||
| var A edwards25519.ExtendedGroupElement | |||
| var hBytes [32]byte | |||
| copy(hBytes[:], digest[:]) | |||
| edwards25519.GeScalarMultBase(&A, &hBytes) | |||
| var publicKeyBytes [32]byte | |||
| A.ToBytes(&publicKeyBytes) | |||
| copy(privateKey[32:], publicKeyBytes[:]) | |||
| copy(publicKey, publicKeyBytes[:]) | |||
| return publicKey, privateKey, nil | |||
| } | |||
| // Sign signs the message with privateKey and returns a signature. It will | |||
| // panic if len(privateKey) is not PrivateKeySize. | |||
| func Sign(privateKey PrivateKey, message []byte) []byte { | |||
| if l := len(privateKey); l != PrivateKeySize { | |||
| panic("ed25519: bad private key length: " + strconv.Itoa(l)) | |||
| } | |||
| h := sha512.New() | |||
| h.Write(privateKey[:32]) | |||
| var digest1, messageDigest, hramDigest [64]byte | |||
| var expandedSecretKey [32]byte | |||
| h.Sum(digest1[:0]) | |||
| copy(expandedSecretKey[:], digest1[:]) | |||
| expandedSecretKey[0] &= 248 | |||
| expandedSecretKey[31] &= 63 | |||
| expandedSecretKey[31] |= 64 | |||
| h.Reset() | |||
| h.Write(digest1[32:]) | |||
| h.Write(message) | |||
| h.Sum(messageDigest[:0]) | |||
| var messageDigestReduced [32]byte | |||
| edwards25519.ScReduce(&messageDigestReduced, &messageDigest) | |||
| var R edwards25519.ExtendedGroupElement | |||
| edwards25519.GeScalarMultBase(&R, &messageDigestReduced) | |||
| var encodedR [32]byte | |||
| R.ToBytes(&encodedR) | |||
| h.Reset() | |||
| h.Write(encodedR[:]) | |||
| h.Write(privateKey[32:]) | |||
| h.Write(message) | |||
| h.Sum(hramDigest[:0]) | |||
| var hramDigestReduced [32]byte | |||
| edwards25519.ScReduce(&hramDigestReduced, &hramDigest) | |||
| var s [32]byte | |||
| edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) | |||
| signature := make([]byte, SignatureSize) | |||
| copy(signature[:], encodedR[:]) | |||
| copy(signature[32:], s[:]) | |||
| return signature | |||
| } | |||
| // Verify reports whether sig is a valid signature of message by publicKey. It | |||
| // will panic if len(publicKey) is not PublicKeySize. | |||
| func Verify(publicKey PublicKey, message, sig []byte) bool { | |||
| if l := len(publicKey); l != PublicKeySize { | |||
| panic("ed25519: bad public key length: " + strconv.Itoa(l)) | |||
| } | |||
| if len(sig) != SignatureSize || sig[63]&224 != 0 { | |||
| return false | |||
| } | |||
| var A edwards25519.ExtendedGroupElement | |||
| var publicKeyBytes [32]byte | |||
| copy(publicKeyBytes[:], publicKey) | |||
| if !A.FromBytes(&publicKeyBytes) { | |||
| return false | |||
| } | |||
| edwards25519.FeNeg(&A.X, &A.X) | |||
| edwards25519.FeNeg(&A.T, &A.T) | |||
| h := sha512.New() | |||
| h.Write(sig[:32]) | |||
| h.Write(publicKey[:]) | |||
| h.Write(message) | |||
| var digest [64]byte | |||
| h.Sum(digest[:0]) | |||
| var hReduced [32]byte | |||
| edwards25519.ScReduce(&hReduced, &digest) | |||
| var R edwards25519.ProjectiveGroupElement | |||
| var b [32]byte | |||
| copy(b[:], sig[32:]) | |||
| edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b) | |||
| var checkR [32]byte | |||
| R.ToBytes(&checkR) | |||
| return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1 | |||
| } | |||
| @@ -4,14 +4,17 @@ | |||
| // Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is | |||
| // very similar to PEM except that it has an additional CRC checksum. | |||
| package armor // import "golang.org/x/crypto/openpgp/armor" | |||
| package armor // import "github.com/keybase/go-crypto/openpgp/armor" | |||
| import ( | |||
| "bufio" | |||
| "bytes" | |||
| "encoding/base64" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "io" | |||
| "strings" | |||
| "unicode" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| ) | |||
| // A Block represents an OpenPGP armored structure. | |||
| @@ -65,7 +68,14 @@ type lineReader struct { | |||
| in *bufio.Reader | |||
| buf []byte | |||
| eof bool | |||
| crc uint32 | |||
| crc *uint32 | |||
| } | |||
| // ourIsSpace checks if a rune is either space according to unicode | |||
| // package, or ZeroWidthSpace (which is not a space according to | |||
| // unicode module). Used to trim lines during header reading. | |||
| func ourIsSpace(r rune) bool { | |||
| return r == '\u200b' || unicode.IsSpace(r) | |||
| } | |||
| func (l *lineReader) Read(p []byte) (n int, err error) { | |||
| @@ -79,13 +89,12 @@ func (l *lineReader) Read(p []byte) (n int, err error) { | |||
| return | |||
| } | |||
| line, isPrefix, err := l.in.ReadLine() | |||
| line, _, err := l.in.ReadLine() | |||
| if err != nil { | |||
| return | |||
| } | |||
| if isPrefix { | |||
| return 0, ArmorCorrupt | |||
| } | |||
| line = bytes.TrimFunc(line, ourIsSpace) | |||
| if len(line) == 5 && line[0] == '=' { | |||
| // This is the checksum line | |||
| @@ -95,13 +104,19 @@ func (l *lineReader) Read(p []byte) (n int, err error) { | |||
| if m != 3 || err != nil { | |||
| return | |||
| } | |||
| l.crc = uint32(expectedBytes[0])<<16 | | |||
| crc := uint32(expectedBytes[0])<<16 | | |||
| uint32(expectedBytes[1])<<8 | | |||
| uint32(expectedBytes[2]) | |||
| l.crc = &crc | |||
| line, _, err = l.in.ReadLine() | |||
| if err != nil && err != io.EOF { | |||
| return | |||
| for { | |||
| line, _, err = l.in.ReadLine() | |||
| if err != nil && err != io.EOF { | |||
| return | |||
| } | |||
| if len(strings.TrimSpace(string(line))) > 0 { | |||
| break | |||
| } | |||
| } | |||
| if !bytes.HasPrefix(line, armorEnd) { | |||
| return 0, ArmorCorrupt | |||
| @@ -111,8 +126,11 @@ func (l *lineReader) Read(p []byte) (n int, err error) { | |||
| return 0, io.EOF | |||
| } | |||
| if len(line) > 96 { | |||
| return 0, ArmorCorrupt | |||
| if bytes.HasPrefix(line, armorEnd) { | |||
| // Unexpected ending, there was no checksum. | |||
| l.eof = true | |||
| l.crc = nil | |||
| return 0, io.EOF | |||
| } | |||
| n = copy(p, line) | |||
| @@ -142,7 +160,7 @@ func (r *openpgpReader) Read(p []byte) (n int, err error) { | |||
| r.currentCRC = crc24(r.currentCRC, p[:n]) | |||
| if err == io.EOF { | |||
| if r.lReader.crc != uint32(r.currentCRC&crc24Mask) { | |||
| if r.lReader.crc != nil && *r.lReader.crc != uint32(r.currentCRC&crc24Mask) { | |||
| return 0, ArmorCorrupt | |||
| } | |||
| } | |||
| @@ -196,7 +214,7 @@ TryNextBlock: | |||
| p.Header[lastKey] += string(line) | |||
| continue | |||
| } | |||
| line = bytes.TrimSpace(line) | |||
| line = bytes.TrimFunc(line, ourIsSpace) | |||
| if len(line) == 0 { | |||
| break | |||
| } | |||
| @@ -125,7 +125,7 @@ func (e *encoding) Close() (err error) { | |||
| var b64ChecksumBytes [4]byte | |||
| base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:]) | |||
| return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine) | |||
| return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine, []byte{'\n'}) | |||
| } | |||
| // Encode returns a WriteCloser which will encode the data written to it in | |||
| @@ -0,0 +1,282 @@ | |||
| package ecdh | |||
| import ( | |||
| "bytes" | |||
| "crypto" | |||
| "crypto/aes" | |||
| "crypto/elliptic" | |||
| "encoding/binary" | |||
| "errors" | |||
| "github.com/keybase/go-crypto/curve25519" | |||
| "io" | |||
| "math/big" | |||
| ) | |||
| type PublicKey struct { | |||
| elliptic.Curve | |||
| X, Y *big.Int | |||
| } | |||
| type PrivateKey struct { | |||
| PublicKey | |||
| X *big.Int | |||
| } | |||
| // KDF implements Key Derivation Function as described in | |||
| // https://tools.ietf.org/html/rfc6637#section-7 | |||
| func (e *PublicKey) KDF(S []byte, kdfParams []byte, hash crypto.Hash) []byte { | |||
| sLen := (e.Curve.Params().P.BitLen() + 7) / 8 | |||
| buf := new(bytes.Buffer) | |||
| buf.Write([]byte{0, 0, 0, 1}) | |||
| if sLen > len(S) { | |||
| // zero-pad the S. If we got invalid S (bigger than curve's | |||
| // P), we are going to produce invalid key. Garbage in, | |||
| // garbage out. | |||
| buf.Write(make([]byte, sLen-len(S))) | |||
| } | |||
| buf.Write(S) | |||
| buf.Write(kdfParams) | |||
| hashw := hash.New() | |||
| hashw.Write(buf.Bytes()) | |||
| key := hashw.Sum(nil) | |||
| return key | |||
| } | |||
| // AESKeyUnwrap implements RFC 3394 Key Unwrapping. See | |||
| // http://tools.ietf.org/html/rfc3394#section-2.2.1 | |||
| // Note: The second described algorithm ("index-based") is implemented | |||
| // here. | |||
| func AESKeyUnwrap(key, cipherText []byte) ([]byte, error) { | |||
| if len(cipherText)%8 != 0 { | |||
| return nil, errors.New("cipherText must by a multiple of 64 bits") | |||
| } | |||
| cipher, err := aes.NewCipher(key) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| nblocks := len(cipherText)/8 - 1 | |||
| // 1) Initialize variables. | |||
| // - Set A = C[0] | |||
| var A [aes.BlockSize]byte | |||
| copy(A[:8], cipherText[:8]) | |||
| // For i = 1 to n | |||
| // Set R[i] = C[i] | |||
| R := make([]byte, len(cipherText)-8) | |||
| copy(R, cipherText[8:]) | |||
| // 2) Compute intermediate values. | |||
| for j := 5; j >= 0; j-- { | |||
| for i := nblocks - 1; i >= 0; i-- { | |||
| // B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i | |||
| // A = MSB(64, B) | |||
| t := uint64(nblocks*j + i + 1) | |||
| At := binary.BigEndian.Uint64(A[:8]) ^ t | |||
| binary.BigEndian.PutUint64(A[:8], At) | |||
| copy(A[8:], R[i*8:i*8+8]) | |||
| cipher.Decrypt(A[:], A[:]) | |||
| // R[i] = LSB(B, 64) | |||
| copy(R[i*8:i*8+8], A[8:]) | |||
| } | |||
| } | |||
| // 3) Output results. | |||
| // If A is an appropriate initial value (see 2.2.3), | |||
| for i := 0; i < 8; i++ { | |||
| if A[i] != 0xA6 { | |||
| return nil, errors.New("Failed to unwrap key (A is not IV)") | |||
| } | |||
| } | |||
| return R, nil | |||
| } | |||
| // AESKeyWrap implements RFC 3394 Key Wrapping. See | |||
| // https://tools.ietf.org/html/rfc3394#section-2.2.2 | |||
| // Note: The second described algorithm ("index-based") is implemented | |||
| // here. | |||
| func AESKeyWrap(key, plainText []byte) ([]byte, error) { | |||
| if len(plainText)%8 != 0 { | |||
| return nil, errors.New("plainText must be a multiple of 64 bits") | |||
| } | |||
| cipher, err := aes.NewCipher(key) // NewCipher checks key size | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| nblocks := len(plainText) / 8 | |||
| // 1) Initialize variables. | |||
| var A [aes.BlockSize]byte | |||
| // Section 2.2.3.1 -- Initial Value | |||
| // http://tools.ietf.org/html/rfc3394#section-2.2.3.1 | |||
| for i := 0; i < 8; i++ { | |||
| A[i] = 0xA6 | |||
| } | |||
| // For i = 1 to n | |||
| // Set R[i] = P[i] | |||
| R := make([]byte, len(plainText)) | |||
| copy(R, plainText) | |||
| // 2) Calculate intermediate values. | |||
| for j := 0; j <= 5; j++ { | |||
| for i := 0; i < nblocks; i++ { | |||
| // B = AES(K, A | R[i]) | |||
| copy(A[8:], R[i*8:i*8+8]) | |||
| cipher.Encrypt(A[:], A[:]) | |||
| // (Assume B = A) | |||
| // A = MSB(64, B) ^ t where t = (n*j)+1 | |||
| t := uint64(j*nblocks + i + 1) | |||
| At := binary.BigEndian.Uint64(A[:8]) ^ t | |||
| binary.BigEndian.PutUint64(A[:8], At) | |||
| // R[i] = LSB(64, B) | |||
| copy(R[i*8:i*8+8], A[8:]) | |||
| } | |||
| } | |||
| // 3) Output results. | |||
| // Set C[0] = A | |||
| // For i = 1 to n | |||
| // C[i] = R[i] | |||
| return append(A[:8], R...), nil | |||
| } | |||
| // PadBuffer pads byte buffer buf to a length being multiple of | |||
| // blockLen. Additional bytes appended to the buffer have value of the | |||
| // number padded bytes. E.g. if the buffer is 3 bytes short of being | |||
| // 40 bytes total, the appended bytes will be [03, 03, 03]. | |||
| func PadBuffer(buf []byte, blockLen int) []byte { | |||
| padding := blockLen - (len(buf) % blockLen) | |||
| if padding == 0 { | |||
| return buf | |||
| } | |||
| padBuf := make([]byte, padding) | |||
| for i := 0; i < padding; i++ { | |||
| padBuf[i] = byte(padding) | |||
| } | |||
| return append(buf, padBuf...) | |||
| } | |||
| // UnpadBuffer verifies that buffer contains proper padding and | |||
| // returns buffer without the padding, or nil if the padding was | |||
| // invalid. | |||
| func UnpadBuffer(buf []byte, dataLen int) []byte { | |||
| padding := len(buf) - dataLen | |||
| outBuf := buf[:dataLen] | |||
| for i := dataLen; i < len(buf); i++ { | |||
| if buf[i] != byte(padding) { | |||
| // Invalid padding - bail out | |||
| return nil | |||
| } | |||
| } | |||
| return outBuf | |||
| } | |||
| func (e *PublicKey) Encrypt(random io.Reader, kdfParams []byte, plain []byte, hash crypto.Hash, kdfKeySize int) (Vx *big.Int, Vy *big.Int, C []byte, err error) { | |||
| // Vx, Vy - encryption key | |||
| // Note for Curve 25519 - curve25519 library already does key | |||
| // clamping in scalarMult, so we can use generic random scalar | |||
| // generation from elliptic. | |||
| priv, Vx, Vy, err := elliptic.GenerateKey(e.Curve, random) | |||
| if err != nil { | |||
| return nil, nil, nil, err | |||
| } | |||
| // Sx, Sy - shared secret | |||
| Sx, _ := e.Curve.ScalarMult(e.X, e.Y, priv) | |||
| // Encrypt the payload with KDF-ed S as the encryption key. Pass | |||
| // the ciphertext along with V to the recipient. Recipient can | |||
| // generate S using V and their priv key, and then KDF(S), on | |||
| // their own, to get encryption key and decrypt the ciphertext, | |||
| // revealing encryption key for symmetric encryption later. | |||
| plain = PadBuffer(plain, 8) | |||
| key := e.KDF(Sx.Bytes(), kdfParams, hash) | |||
| // Take only as many bytes from key as the key length (the hash | |||
| // result might be bigger) | |||
| encrypted, err := AESKeyWrap(key[:kdfKeySize], plain) | |||
| return Vx, Vy, encrypted, nil | |||
| } | |||
| func (e *PrivateKey) DecryptShared(X, Y *big.Int) []byte { | |||
| Sx, _ := e.Curve.ScalarMult(X, Y, e.X.Bytes()) | |||
| return Sx.Bytes() | |||
| } | |||
| func countBits(buffer []byte) int { | |||
| var headerLen int | |||
| switch buffer[0] { | |||
| case 0x4: | |||
| headerLen = 3 | |||
| case 0x40: | |||
| headerLen = 7 | |||
| default: | |||
| // Unexpected header - but we can still count the bits. | |||
| val := buffer[0] | |||
| headerLen = 0 | |||
| for val > 0 { | |||
| val = val / 2 | |||
| headerLen++ | |||
| } | |||
| } | |||
| return headerLen + (len(buffer)-1)*8 | |||
| } | |||
| // elliptic.Marshal and elliptic.Unmarshal only marshals uncompressed | |||
| // 0x4 MPI types. These functions will check if the curve is cv25519, | |||
| // and if so, use 0x40 compressed type to (un)marshal. Otherwise, | |||
| // elliptic.(Un)marshal will be called. | |||
| // Marshal encodes point into either 0x4 uncompressed point form, or | |||
| // 0x40 compressed point for Curve 25519. | |||
| func Marshal(curve elliptic.Curve, x, y *big.Int) (buf []byte, bitSize int) { | |||
| // NOTE: Read more about MPI encoding in the RFC: | |||
| // https://tools.ietf.org/html/rfc4880#section-3.2 | |||
| // We are required to encode size in bits, counting from the most- | |||
| // significant non-zero bit. So assuming that the buffer never | |||
| // starts with 0x00, we only need to count bits in the first byte | |||
| // - and in current implentation it will always be 0x4 or 0x40. | |||
| cv, ok := curve25519.ToCurve25519(curve) | |||
| if ok { | |||
| buf = cv.MarshalType40(x, y) | |||
| } else { | |||
| buf = elliptic.Marshal(curve, x, y) | |||
| } | |||
| return buf, countBits(buf) | |||
| } | |||
| // Unmarshal converts point, serialized by Marshal, into x, y pair. | |||
| // For 0x40 compressed points (for Curve 25519), y will always be 0. | |||
| // It is an error if point is not on the curve, On error, x = nil. | |||
| func Unmarshal(curve elliptic.Curve, data []byte) (x, y *big.Int) { | |||
| cv, ok := curve25519.ToCurve25519(curve) | |||
| if ok { | |||
| return cv.UnmarshalType40(data) | |||
| } | |||
| return elliptic.Unmarshal(curve, data) | |||
| } | |||
| @@ -10,7 +10,7 @@ | |||
| // This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it | |||
| // unsuitable for other protocols. RSA should be used in preference in any | |||
| // case. | |||
| package elgamal // import "golang.org/x/crypto/openpgp/elgamal" | |||
| package elgamal // import "github.com/keybase/go-crypto/openpgp/elgamal" | |||
| import ( | |||
| "crypto/rand" | |||
| @@ -3,7 +3,7 @@ | |||
| // license that can be found in the LICENSE file. | |||
| // Package errors contains common error types for the OpenPGP packages. | |||
| package errors // import "golang.org/x/crypto/openpgp/errors" | |||
| package errors // import "github.com/keybase/go-crypto/openpgp/errors" | |||
| import ( | |||
| "strconv" | |||
| @@ -0,0 +1,902 @@ | |||
| // Copyright 2011 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package openpgp | |||
| import ( | |||
| "crypto/hmac" | |||
| "encoding/binary" | |||
| "io" | |||
| "time" | |||
| "github.com/keybase/go-crypto/openpgp/armor" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/packet" | |||
| "github.com/keybase/go-crypto/rsa" | |||
| ) | |||
| // PublicKeyType is the armor type for a PGP public key. | |||
| var PublicKeyType = "PGP PUBLIC KEY BLOCK" | |||
| // PrivateKeyType is the armor type for a PGP private key. | |||
| var PrivateKeyType = "PGP PRIVATE KEY BLOCK" | |||
| // An Entity represents the components of an OpenPGP key: a primary public key | |||
| // (which must be a signing key), one or more identities claimed by that key, | |||
| // and zero or more subkeys, which may be encryption keys. | |||
| type Entity struct { | |||
| PrimaryKey *packet.PublicKey | |||
| PrivateKey *packet.PrivateKey | |||
| Identities map[string]*Identity // indexed by Identity.Name | |||
| Revocations []*packet.Signature | |||
| // Revocations that are signed by designated revokers. Reading keys | |||
| // will not verify these revocations, because it won't have access to | |||
| // issuers' public keys, API consumers should do this instead (or | |||
| // not, and just assume that the key is probably revoked). | |||
| UnverifiedRevocations []*packet.Signature | |||
| Subkeys []Subkey | |||
| BadSubkeys []BadSubkey | |||
| } | |||
| // An Identity represents an identity claimed by an Entity and zero or more | |||
| // assertions by other entities about that claim. | |||
| type Identity struct { | |||
| Name string // by convention, has the form "Full Name (comment) <email@example.com>" | |||
| UserId *packet.UserId | |||
| SelfSignature *packet.Signature | |||
| Signatures []*packet.Signature | |||
| Revocation *packet.Signature | |||
| } | |||
| // A Subkey is an additional public key in an Entity. Subkeys can be used for | |||
| // encryption. | |||
| type Subkey struct { | |||
| PublicKey *packet.PublicKey | |||
| PrivateKey *packet.PrivateKey | |||
| Sig *packet.Signature | |||
| Revocation *packet.Signature | |||
| } | |||
| // BadSubkey is one that failed reconstruction, but we'll keep it around for | |||
| // informational purposes. | |||
| type BadSubkey struct { | |||
| Subkey | |||
| Err error | |||
| } | |||
| // A Key identifies a specific public key in an Entity. This is either the | |||
| // Entity's primary key or a subkey. | |||
| type Key struct { | |||
| Entity *Entity | |||
| PublicKey *packet.PublicKey | |||
| PrivateKey *packet.PrivateKey | |||
| SelfSignature *packet.Signature | |||
| KeyFlags packet.KeyFlagBits | |||
| } | |||
| // A KeyRing provides access to public and private keys. | |||
| type KeyRing interface { | |||
| // KeysById returns the set of keys that have the given key id. | |||
| // fp can be optionally supplied, which is the full key fingerprint. | |||
| // If it's provided, then it must match. This comes up in the case | |||
| // of GPG subpacket 33. | |||
| KeysById(id uint64, fp []byte) []Key | |||
| // KeysByIdAndUsage returns the set of keys with the given id | |||
| // that also meet the key usage given by requiredUsage. | |||
| // The requiredUsage is expressed as the bitwise-OR of | |||
| // packet.KeyFlag* values. | |||
| // fp can be optionally supplied, which is the full key fingerprint. | |||
| // If it's provided, then it must match. This comes up in the case | |||
| // of GPG subpacket 33. | |||
| KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) []Key | |||
| // DecryptionKeys returns all private keys that are valid for | |||
| // decryption. | |||
| DecryptionKeys() []Key | |||
| } | |||
| // primaryIdentity returns the Identity marked as primary or the first identity | |||
| // if none are so marked. | |||
| func (e *Entity) primaryIdentity() *Identity { | |||
| var firstIdentity *Identity | |||
| for _, ident := range e.Identities { | |||
| if firstIdentity == nil { | |||
| firstIdentity = ident | |||
| } | |||
| if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { | |||
| return ident | |||
| } | |||
| } | |||
| return firstIdentity | |||
| } | |||
| // encryptionKey returns the best candidate Key for encrypting a message to the | |||
| // given Entity. | |||
| func (e *Entity) encryptionKey(now time.Time) (Key, bool) { | |||
| candidateSubkey := -1 | |||
| // Iterate the keys to find the newest key | |||
| var maxTime time.Time | |||
| for i, subkey := range e.Subkeys { | |||
| // NOTE(maxtaco) | |||
| // If there is a Flags subpacket, then we have to follow it, and only | |||
| // use keys that are marked for Encryption of Communication. If there | |||
| // isn't a Flags subpacket, and this is an Encrypt-Only key (right now only ElGamal | |||
| // suffices), then we implicitly use it. The check for primary below is a little | |||
| // more open-ended, but for now, let's be strict and potentially open up | |||
| // if we see bugs in the wild. | |||
| // | |||
| // One more note: old DSA/ElGamal keys tend not to have the Flags subpacket, | |||
| // so this sort of thing is pretty important for encrypting to older keys. | |||
| // | |||
| if ((subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications) || | |||
| (!subkey.Sig.FlagsValid && subkey.PublicKey.PubKeyAlgo == packet.PubKeyAlgoElGamal)) && | |||
| subkey.PublicKey.PubKeyAlgo.CanEncrypt() && | |||
| !subkey.Sig.KeyExpired(now) && | |||
| subkey.Revocation == nil && | |||
| (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { | |||
| candidateSubkey = i | |||
| maxTime = subkey.Sig.CreationTime | |||
| } | |||
| } | |||
| if candidateSubkey != -1 { | |||
| subkey := e.Subkeys[candidateSubkey] | |||
| return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Sig.GetKeyFlags()}, true | |||
| } | |||
| // If we don't have any candidate subkeys for encryption and | |||
| // the primary key doesn't have any usage metadata then we | |||
| // assume that the primary key is ok. Or, if the primary key is | |||
| // marked as ok to encrypt to, then we can obviously use it. | |||
| // | |||
| // NOTE(maxtaco) - see note above, how this policy is a little too open-ended | |||
| // for my liking, but leave it for now. | |||
| i := e.primaryIdentity() | |||
| if (!i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications) && | |||
| e.PrimaryKey.PubKeyAlgo.CanEncrypt() && | |||
| !i.SelfSignature.KeyExpired(now) { | |||
| return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, i.SelfSignature.GetKeyFlags()}, true | |||
| } | |||
| // This Entity appears to be signing only. | |||
| return Key{}, false | |||
| } | |||
| // signingKey return the best candidate Key for signing a message with this | |||
| // Entity. | |||
| func (e *Entity) signingKey(now time.Time) (Key, bool) { | |||
| candidateSubkey := -1 | |||
| for i, subkey := range e.Subkeys { | |||
| if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) && | |||
| subkey.PrivateKey.PrivateKey != nil && | |||
| subkey.PublicKey.PubKeyAlgo.CanSign() && | |||
| subkey.Revocation == nil && | |||
| !subkey.Sig.KeyExpired(now) { | |||
| candidateSubkey = i | |||
| break | |||
| } | |||
| } | |||
| if candidateSubkey != -1 { | |||
| subkey := e.Subkeys[candidateSubkey] | |||
| return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Sig.GetKeyFlags()}, true | |||
| } | |||
| // If we have no candidate subkey then we assume that it's ok to sign | |||
| // with the primary key. | |||
| i := e.primaryIdentity() | |||
| if (!i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign) && | |||
| e.PrimaryKey.PubKeyAlgo.CanSign() && | |||
| !i.SelfSignature.KeyExpired(now) && | |||
| e.PrivateKey.PrivateKey != nil { | |||
| return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, i.SelfSignature.GetKeyFlags()}, true | |||
| } | |||
| return Key{}, false | |||
| } | |||
| // An EntityList contains one or more Entities. | |||
| type EntityList []*Entity | |||
| func keyMatchesIdAndFingerprint(key *packet.PublicKey, id uint64, fp []byte) bool { | |||
| if key.KeyId != id { | |||
| return false | |||
| } | |||
| if fp == nil { | |||
| return true | |||
| } | |||
| return hmac.Equal(fp, key.Fingerprint[:]) | |||
| } | |||
| // KeysById returns the set of keys that have the given key id. | |||
| // fp can be optionally supplied, which is the full key fingerprint. | |||
| // If it's provided, then it must match. This comes up in the case | |||
| // of GPG subpacket 33. | |||
| func (el EntityList) KeysById(id uint64, fp []byte) (keys []Key) { | |||
| for _, e := range el { | |||
| if keyMatchesIdAndFingerprint(e.PrimaryKey, id, fp) { | |||
| var selfSig *packet.Signature | |||
| for _, ident := range e.Identities { | |||
| if selfSig == nil { | |||
| selfSig = ident.SelfSignature | |||
| } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { | |||
| selfSig = ident.SelfSignature | |||
| break | |||
| } | |||
| } | |||
| var keyFlags packet.KeyFlagBits | |||
| for _, ident := range e.Identities { | |||
| keyFlags.Merge(ident.SelfSignature.GetKeyFlags()) | |||
| } | |||
| keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, keyFlags}) | |||
| } | |||
| for _, subKey := range e.Subkeys { | |||
| if keyMatchesIdAndFingerprint(subKey.PublicKey, id, fp) { | |||
| // If there's both a a revocation and a sig, then take the | |||
| // revocation. Otherwise, we can proceed with the sig. | |||
| sig := subKey.Revocation | |||
| if sig == nil { | |||
| sig = subKey.Sig | |||
| } | |||
| keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, sig, sig.GetKeyFlags()}) | |||
| } | |||
| } | |||
| } | |||
| return | |||
| } | |||
| // KeysByIdAndUsage returns the set of keys with the given id that also meet | |||
| // the key usage given by requiredUsage. The requiredUsage is expressed as | |||
| // the bitwise-OR of packet.KeyFlag* values. | |||
| // fp can be optionally supplied, which is the full key fingerprint. | |||
| // If it's provided, then it must match. This comes up in the case | |||
| // of GPG subpacket 33. | |||
| func (el EntityList) KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) (keys []Key) { | |||
| for _, key := range el.KeysById(id, fp) { | |||
| if len(key.Entity.Revocations) > 0 { | |||
| continue | |||
| } | |||
| if key.SelfSignature.RevocationReason != nil { | |||
| continue | |||
| } | |||
| if requiredUsage != 0 { | |||
| var usage byte | |||
| switch { | |||
| case key.KeyFlags.Valid: | |||
| usage = key.KeyFlags.BitField | |||
| case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoElGamal: | |||
| // We also need to handle the case where, although the sig's | |||
| // flags aren't valid, the key can is implicitly usable for | |||
| // encryption by virtue of being ElGamal. See also the comment | |||
| // in encryptionKey() above. | |||
| usage |= packet.KeyFlagEncryptCommunications | |||
| usage |= packet.KeyFlagEncryptStorage | |||
| case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoDSA || | |||
| key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoECDSA || | |||
| key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA: | |||
| usage |= packet.KeyFlagSign | |||
| // For a primary RSA key without any key flags, be as permissiable | |||
| // as possible. | |||
| case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoRSA && | |||
| keyMatchesIdAndFingerprint(key.Entity.PrimaryKey, id, fp): | |||
| usage = (packet.KeyFlagCertify | packet.KeyFlagSign | | |||
| packet.KeyFlagEncryptCommunications | packet.KeyFlagEncryptStorage) | |||
| } | |||
| if usage&requiredUsage != requiredUsage { | |||
| continue | |||
| } | |||
| } | |||
| keys = append(keys, key) | |||
| } | |||
| return | |||
| } | |||
| // DecryptionKeys returns all private keys that are valid for decryption. | |||
| func (el EntityList) DecryptionKeys() (keys []Key) { | |||
| for _, e := range el { | |||
| for _, subKey := range e.Subkeys { | |||
| if subKey.PrivateKey != nil && subKey.PrivateKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) { | |||
| keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Sig.GetKeyFlags()}) | |||
| } | |||
| } | |||
| } | |||
| return | |||
| } | |||
| // ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file. | |||
| func ReadArmoredKeyRing(r io.Reader) (EntityList, error) { | |||
| block, err := armor.Decode(r) | |||
| if err == io.EOF { | |||
| return nil, errors.InvalidArgumentError("no armored data found") | |||
| } | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if block.Type != PublicKeyType && block.Type != PrivateKeyType { | |||
| return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type) | |||
| } | |||
| return ReadKeyRing(block.Body) | |||
| } | |||
| // ReadKeyRing reads one or more public/private keys. Unsupported keys are | |||
| // ignored as long as at least a single valid key is found. | |||
| func ReadKeyRing(r io.Reader) (el EntityList, err error) { | |||
| packets := packet.NewReader(r) | |||
| var lastUnsupportedError error | |||
| for { | |||
| var e *Entity | |||
| e, err = ReadEntity(packets) | |||
| if err != nil { | |||
| // TODO: warn about skipped unsupported/unreadable keys | |||
| if _, ok := err.(errors.UnsupportedError); ok { | |||
| lastUnsupportedError = err | |||
| err = readToNextPublicKey(packets) | |||
| } else if _, ok := err.(errors.StructuralError); ok { | |||
| // Skip unreadable, badly-formatted keys | |||
| lastUnsupportedError = err | |||
| err = readToNextPublicKey(packets) | |||
| } | |||
| if err == io.EOF { | |||
| err = nil | |||
| break | |||
| } | |||
| if err != nil { | |||
| el = nil | |||
| break | |||
| } | |||
| } else { | |||
| el = append(el, e) | |||
| } | |||
| } | |||
| if len(el) == 0 && err == nil { | |||
| err = lastUnsupportedError | |||
| } | |||
| return | |||
| } | |||
| // readToNextPublicKey reads packets until the start of the entity and leaves | |||
| // the first packet of the new entity in the Reader. | |||
| func readToNextPublicKey(packets *packet.Reader) (err error) { | |||
| var p packet.Packet | |||
| for { | |||
| p, err = packets.Next() | |||
| if err == io.EOF { | |||
| return | |||
| } else if err != nil { | |||
| if _, ok := err.(errors.UnsupportedError); ok { | |||
| err = nil | |||
| continue | |||
| } | |||
| return | |||
| } | |||
| if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey { | |||
| packets.Unread(p) | |||
| return | |||
| } | |||
| } | |||
| panic("unreachable") | |||
| } | |||
| // ReadEntity reads an entity (public key, identities, subkeys etc) from the | |||
| // given Reader. | |||
| func ReadEntity(packets *packet.Reader) (*Entity, error) { | |||
| e := new(Entity) | |||
| e.Identities = make(map[string]*Identity) | |||
| p, err := packets.Next() | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| var ok bool | |||
| if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok { | |||
| if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { | |||
| packets.Unread(p) | |||
| return nil, errors.StructuralError("first packet was not a public/private key") | |||
| } else { | |||
| e.PrimaryKey = &e.PrivateKey.PublicKey | |||
| } | |||
| } | |||
| if !e.PrimaryKey.PubKeyAlgo.CanSign() { | |||
| return nil, errors.StructuralError("primary key cannot be used for signatures") | |||
| } | |||
| var current *Identity | |||
| var revocations []*packet.Signature | |||
| designatedRevokers := make(map[uint64]bool) | |||
| EachPacket: | |||
| for { | |||
| p, err := packets.Next() | |||
| if err == io.EOF { | |||
| break | |||
| } else if err != nil { | |||
| return nil, err | |||
| } | |||
| switch pkt := p.(type) { | |||
| case *packet.UserId: | |||
| // Make a new Identity object, that we might wind up throwing away. | |||
| // We'll only add it if we get a valid self-signature over this | |||
| // userID. | |||
| current = new(Identity) | |||
| current.Name = pkt.Id | |||
| current.UserId = pkt | |||
| case *packet.Signature: | |||
| if pkt.SigType == packet.SigTypeKeyRevocation { | |||
| // These revocations won't revoke UIDs (see | |||
| // SigTypeIdentityRevocation). Handle these first, | |||
| // because key might have revocation coming from | |||
| // another key (designated revoke). | |||
| revocations = append(revocations, pkt) | |||
| continue | |||
| } | |||
| // These are signatures by other people on this key. Let's just ignore them | |||
| // from the beginning, since they shouldn't affect our key decoding one way | |||
| // or the other. | |||
| if pkt.IssuerKeyId != nil && *pkt.IssuerKeyId != e.PrimaryKey.KeyId { | |||
| continue | |||
| } | |||
| // If this is a signature made by the keyholder, and the signature has stubbed out | |||
| // critical packets, then *now* we need to bail out. | |||
| if e := pkt.StubbedOutCriticalError; e != nil { | |||
| return nil, e | |||
| } | |||
| // Next handle the case of a self-signature. According to RFC8440, | |||
| // Section 5.2.3.3, if there are several self-signatures, | |||
| // we should take the newer one. If they were both created | |||
| // at the same time, but one of them has keyflags specified and the | |||
| // other doesn't, keep the one with the keyflags. We have actually | |||
| // seen this in the wild (see the 'Yield' test in read_test.go). | |||
| // If there is a tie, and both have the same value for FlagsValid, | |||
| // then "last writer wins." | |||
| // | |||
| // HOWEVER! We have seen yet more keys in the wild (see the 'Spiros' | |||
| // test in read_test.go), in which the later self-signature is a bunch | |||
| // of junk, and doesn't even specify key flags. Does it really make | |||
| // sense to overwrite reasonable key flags with the empty set? I'm not | |||
| // sure what that would be trying to achieve, and plus GPG seems to be | |||
| // ok with this situation, and ignores the later (empty) keyflag set. | |||
| // So further tighten our overwrite rules, and only allow the later | |||
| // signature to overwrite the earlier signature if so doing won't | |||
| // trash the key flags. | |||
| if current != nil && | |||
| (current.SelfSignature == nil || | |||
| (!pkt.CreationTime.Before(current.SelfSignature.CreationTime) && | |||
| (pkt.FlagsValid || !current.SelfSignature.FlagsValid))) && | |||
| (pkt.SigType == packet.SigTypePositiveCert || pkt.SigType == packet.SigTypeGenericCert) && | |||
| pkt.IssuerKeyId != nil && | |||
| *pkt.IssuerKeyId == e.PrimaryKey.KeyId { | |||
| if err = e.PrimaryKey.VerifyUserIdSignature(current.Name, e.PrimaryKey, pkt); err == nil { | |||
| current.SelfSignature = pkt | |||
| // NOTE(maxtaco) 2016.01.11 | |||
| // Only register an identity once we've gotten a valid self-signature. | |||
| // It's possible therefore for us to throw away `current` in the case | |||
| // no valid self-signatures were found. That's OK as long as there are | |||
| // other identies that make sense. | |||
| // | |||
| // NOTE! We might later see a revocation for this very same UID, and it | |||
| // won't be undone. We've preserved this feature from the original | |||
| // Google OpenPGP we forked from. | |||
| e.Identities[current.Name] = current | |||
| } else { | |||
| // We really should warn that there was a failure here. Not raise an error | |||
| // since this really shouldn't be a fail-stop error. | |||
| } | |||
| } else if current != nil && pkt.SigType == packet.SigTypeIdentityRevocation { | |||
| if err = e.PrimaryKey.VerifyUserIdSignature(current.Name, e.PrimaryKey, pkt); err == nil { | |||
| // Note: we are not removing the identity from | |||
| // e.Identities. Caller can always filter by Revocation | |||
| // field to ignore revoked identities. | |||
| current.Revocation = pkt | |||
| } | |||
| } else if pkt.SigType == packet.SigTypeDirectSignature { | |||
| if err = e.PrimaryKey.VerifyRevocationSignature(e.PrimaryKey, pkt); err == nil { | |||
| if desig := pkt.DesignatedRevoker; desig != nil { | |||
| // If it's a designated revoker signature, take last 8 octects | |||
| // of fingerprint as Key ID and save it to designatedRevokers | |||
| // map. We consult this map later to see if a foreign | |||
| // revocation should be added to UnverifiedRevocations. | |||
| keyID := binary.BigEndian.Uint64(desig.Fingerprint[len(desig.Fingerprint)-8:]) | |||
| designatedRevokers[keyID] = true | |||
| } | |||
| } | |||
| } else if current == nil { | |||
| // NOTE(maxtaco) | |||
| // | |||
| // See https://github.com/keybase/client/issues/2666 | |||
| // | |||
| // There might have been a user attribute picture before this signature, | |||
| // in which case this is still a valid PGP key. In the future we might | |||
| // not ignore user attributes (like picture). But either way, it doesn't | |||
| // make sense to bail out here. Keep looking for other valid signatures. | |||
| // | |||
| // Used to be: | |||
| // return nil, errors.StructuralError("signature packet found before user id packet") | |||
| } else { | |||
| current.Signatures = append(current.Signatures, pkt) | |||
| } | |||
| case *packet.PrivateKey: | |||
| if pkt.IsSubkey == false { | |||
| packets.Unread(p) | |||
| break EachPacket | |||
| } | |||
| err = addSubkey(e, packets, &pkt.PublicKey, pkt) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| case *packet.PublicKey: | |||
| if pkt.IsSubkey == false { | |||
| packets.Unread(p) | |||
| break EachPacket | |||
| } | |||
| err = addSubkey(e, packets, pkt, nil) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| default: | |||
| // we ignore unknown packets | |||
| } | |||
| } | |||
| if len(e.Identities) == 0 { | |||
| return nil, errors.StructuralError("entity without any identities") | |||
| } | |||
| for _, revocation := range revocations { | |||
| if revocation.IssuerKeyId == nil || *revocation.IssuerKeyId == e.PrimaryKey.KeyId { | |||
| // Key revokes itself, something that we can verify. | |||
| err = e.PrimaryKey.VerifyRevocationSignature(e.PrimaryKey, revocation) | |||
| if err == nil { | |||
| e.Revocations = append(e.Revocations, revocation) | |||
| } else { | |||
| return nil, errors.StructuralError("revocation signature signed by alternate key") | |||
| } | |||
| } else if revocation.IssuerKeyId != nil { | |||
| if _, ok := designatedRevokers[*revocation.IssuerKeyId]; ok { | |||
| // Revocation is done by certified designated revoker, | |||
| // but we can't verify the revocation. | |||
| e.UnverifiedRevocations = append(e.UnverifiedRevocations, revocation) | |||
| } | |||
| } | |||
| } | |||
| return e, nil | |||
| } | |||
| func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { | |||
| var subKey Subkey | |||
| subKey.PublicKey = pub | |||
| subKey.PrivateKey = priv | |||
| var lastErr error | |||
| for { | |||
| p, err := packets.Next() | |||
| if err == io.EOF { | |||
| break | |||
| } | |||
| if err != nil { | |||
| return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||
| } | |||
| sig, ok := p.(*packet.Signature) | |||
| if !ok { | |||
| // Hit a non-signature packet, so assume we're up to the next key | |||
| packets.Unread(p) | |||
| break | |||
| } | |||
| if st := sig.SigType; st != packet.SigTypeSubkeyBinding && st != packet.SigTypeSubkeyRevocation { | |||
| // Note(maxtaco): | |||
| // We used to error out here, but instead, let's fast-forward past | |||
| // packets that are in the wrong place (like misplaced 0x13 signatures) | |||
| // until we get to one that works. For a test case, | |||
| // see TestWithBadSubkeySignaturePackets. | |||
| continue | |||
| } | |||
| err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig) | |||
| if err != nil { | |||
| // Non valid signature, so again, no need to abandon all hope, just continue; | |||
| // make a note of the error we hit. | |||
| lastErr = errors.StructuralError("subkey signature invalid: " + err.Error()) | |||
| continue | |||
| } | |||
| switch sig.SigType { | |||
| case packet.SigTypeSubkeyBinding: | |||
| // Does the "new" sig set expiration to later date than | |||
| // "previous" sig? | |||
| if subKey.Sig == nil || subKey.Sig.ExpiresBeforeOther(sig) { | |||
| subKey.Sig = sig | |||
| } | |||
| case packet.SigTypeSubkeyRevocation: | |||
| // First writer wins | |||
| if subKey.Revocation == nil { | |||
| subKey.Revocation = sig | |||
| } | |||
| } | |||
| } | |||
| if subKey.Sig != nil { | |||
| e.Subkeys = append(e.Subkeys, subKey) | |||
| } else { | |||
| if lastErr == nil { | |||
| lastErr = errors.StructuralError("Subkey wasn't signed; expected a 'binding' signature") | |||
| } | |||
| e.BadSubkeys = append(e.BadSubkeys, BadSubkey{Subkey: subKey, Err: lastErr}) | |||
| } | |||
| return nil | |||
| } | |||
| const defaultRSAKeyBits = 2048 | |||
| // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a | |||
| // single identity composed of the given full name, comment and email, any of | |||
| // which may be empty but must not contain any of "()<>\x00". | |||
| // If config is nil, sensible defaults will be used. | |||
| func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { | |||
| currentTime := config.Now() | |||
| bits := defaultRSAKeyBits | |||
| if config != nil && config.RSABits != 0 { | |||
| bits = config.RSABits | |||
| } | |||
| uid := packet.NewUserId(name, comment, email) | |||
| if uid == nil { | |||
| return nil, errors.InvalidArgumentError("user id field contained invalid characters") | |||
| } | |||
| signingPriv, err := rsa.GenerateKey(config.Random(), bits) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| encryptingPriv, err := rsa.GenerateKey(config.Random(), bits) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| e := &Entity{ | |||
| PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey), | |||
| PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv), | |||
| Identities: make(map[string]*Identity), | |||
| } | |||
| isPrimaryId := true | |||
| e.Identities[uid.Id] = &Identity{ | |||
| Name: uid.Name, | |||
| UserId: uid, | |||
| SelfSignature: &packet.Signature{ | |||
| CreationTime: currentTime, | |||
| SigType: packet.SigTypePositiveCert, | |||
| PubKeyAlgo: packet.PubKeyAlgoRSA, | |||
| Hash: config.Hash(), | |||
| IsPrimaryId: &isPrimaryId, | |||
| FlagsValid: true, | |||
| FlagSign: true, | |||
| FlagCertify: true, | |||
| IssuerKeyId: &e.PrimaryKey.KeyId, | |||
| }, | |||
| } | |||
| e.Subkeys = make([]Subkey, 1) | |||
| e.Subkeys[0] = Subkey{ | |||
| PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), | |||
| PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv), | |||
| Sig: &packet.Signature{ | |||
| CreationTime: currentTime, | |||
| SigType: packet.SigTypeSubkeyBinding, | |||
| PubKeyAlgo: packet.PubKeyAlgoRSA, | |||
| Hash: config.Hash(), | |||
| FlagsValid: true, | |||
| FlagEncryptStorage: true, | |||
| FlagEncryptCommunications: true, | |||
| IssuerKeyId: &e.PrimaryKey.KeyId, | |||
| }, | |||
| } | |||
| e.Subkeys[0].PublicKey.IsSubkey = true | |||
| e.Subkeys[0].PrivateKey.IsSubkey = true | |||
| return e, nil | |||
| } | |||
| // SerializePrivate serializes an Entity, including private key material, to | |||
| // the given Writer. For now, it must only be used on an Entity returned from | |||
| // NewEntity. | |||
| // If config is nil, sensible defaults will be used. | |||
| func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { | |||
| err = e.PrivateKey.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| for _, ident := range e.Identities { | |||
| err = ident.UserId.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| if e.PrivateKey.PrivateKey != nil { | |||
| err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) | |||
| if err != nil { | |||
| return | |||
| } | |||
| } | |||
| err = ident.SelfSignature.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| } | |||
| for _, subkey := range e.Subkeys { | |||
| err = subkey.PrivateKey.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| // Workaround shortcoming of SignKey(), which doesn't work to reverse-sign | |||
| // sub-signing keys. So if requested, just reuse the signatures already | |||
| // available to us (if we read this key from a keyring). | |||
| if e.PrivateKey.PrivateKey != nil && !config.ReuseSignatures() { | |||
| err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | |||
| if err != nil { | |||
| return | |||
| } | |||
| } | |||
| if subkey.Revocation != nil { | |||
| err = subkey.Revocation.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| } | |||
| err = subkey.Sig.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| // Serialize writes the public part of the given Entity to w. (No private | |||
| // key material will be output). | |||
| func (e *Entity) Serialize(w io.Writer) error { | |||
| err := e.PrimaryKey.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| for _, ident := range e.Identities { | |||
| err = ident.UserId.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| err = ident.SelfSignature.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| for _, sig := range ident.Signatures { | |||
| err = sig.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| for _, subkey := range e.Subkeys { | |||
| err = subkey.PublicKey.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| if subkey.Revocation != nil { | |||
| err = subkey.Revocation.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| err = subkey.Sig.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| // SignIdentity adds a signature to e, from signer, attesting that identity is | |||
| // associated with e. The provided identity must already be an element of | |||
| // e.Identities and the private key of signer must have been decrypted if | |||
| // necessary. | |||
| // If config is nil, sensible defaults will be used. | |||
| func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error { | |||
| if signer.PrivateKey == nil { | |||
| return errors.InvalidArgumentError("signing Entity must have a private key") | |||
| } | |||
| if signer.PrivateKey.Encrypted { | |||
| return errors.InvalidArgumentError("signing Entity's private key must be decrypted") | |||
| } | |||
| ident, ok := e.Identities[identity] | |||
| if !ok { | |||
| return errors.InvalidArgumentError("given identity string not found in Entity") | |||
| } | |||
| sig := &packet.Signature{ | |||
| SigType: packet.SigTypeGenericCert, | |||
| PubKeyAlgo: signer.PrivateKey.PubKeyAlgo, | |||
| Hash: config.Hash(), | |||
| CreationTime: config.Now(), | |||
| IssuerKeyId: &signer.PrivateKey.KeyId, | |||
| } | |||
| if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil { | |||
| return err | |||
| } | |||
| ident.Signatures = append(ident.Signatures, sig) | |||
| return nil | |||
| } | |||
| // CopySubkeyRevocations copies subkey revocations from the src Entity over | |||
| // to the receiver entity. We need this because `gpg --export-secret-key` does | |||
| // not appear to output subkey revocations. In this case we need to manually | |||
| // merge with the output of `gpg --export`. | |||
| func (e *Entity) CopySubkeyRevocations(src *Entity) { | |||
| m := make(map[[20]byte]*packet.Signature) | |||
| for _, subkey := range src.Subkeys { | |||
| if subkey.Revocation != nil { | |||
| m[subkey.PublicKey.Fingerprint] = subkey.Revocation | |||
| } | |||
| } | |||
| for i, subkey := range e.Subkeys { | |||
| if r := m[subkey.PublicKey.Fingerprint]; r != nil { | |||
| e.Subkeys[i].Revocation = r | |||
| } | |||
| } | |||
| } | |||
| // CheckDesignatedRevokers will try to confirm any of designated | |||
| // revocation of entity. For this function to work, revocation | |||
| // issuer's key should be found in keyring. First successfully | |||
| // verified designated revocation is returned along with the key that | |||
| // verified it. | |||
| func FindVerifiedDesignatedRevoke(keyring KeyRing, entity *Entity) (*packet.Signature, *Key) { | |||
| for _, sig := range entity.UnverifiedRevocations { | |||
| if sig.IssuerKeyId == nil { | |||
| continue | |||
| } | |||
| issuerKeyId := *sig.IssuerKeyId | |||
| issuerFingerprint := sig.IssuerFingerprint | |||
| keys := keyring.KeysByIdUsage(issuerKeyId, issuerFingerprint, packet.KeyFlagSign) | |||
| if len(keys) == 0 { | |||
| continue | |||
| } | |||
| for _, key := range keys { | |||
| err := key.PublicKey.VerifyRevocationSignature(entity.PrimaryKey, sig) | |||
| if err == nil { | |||
| return sig, &key | |||
| } | |||
| } | |||
| } | |||
| return nil, nil | |||
| } | |||
| @@ -8,9 +8,10 @@ import ( | |||
| "compress/bzip2" | |||
| "compress/flate" | |||
| "compress/zlib" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "io" | |||
| "strconv" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| ) | |||
| // Compressed represents a compressed OpenPGP packet. The decompressed contents | |||
| @@ -46,6 +46,9 @@ type Config struct { | |||
| // RSABits is the number of bits in new RSA keys made with NewEntity. | |||
| // If zero, then 2048 bit keys are created. | |||
| RSABits int | |||
| // ReuseSignatures tells us to reuse existing Signatures | |||
| // on serialized output. | |||
| ReuseSignaturesOnSerialize bool | |||
| } | |||
| func (c *Config) Random() io.Reader { | |||
| @@ -89,3 +92,7 @@ func (c *Config) PasswordHashIterations() int { | |||
| } | |||
| return c.S2KCount | |||
| } | |||
| func (c *Config) ReuseSignatures() bool { | |||
| return c != nil && c.ReuseSignaturesOnSerialize | |||
| } | |||
| @@ -0,0 +1,104 @@ | |||
| package packet | |||
| import ( | |||
| "bytes" | |||
| "io" | |||
| "math/big" | |||
| "github.com/keybase/go-crypto/openpgp/ecdh" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/s2k" | |||
| ) | |||
| // ECDHKdfParams generates KDF parameters sequence for given | |||
| // PublicKey. See https://tools.ietf.org/html/rfc6637#section-8 | |||
| func ECDHKdfParams(pub *PublicKey) []byte { | |||
| buf := new(bytes.Buffer) | |||
| oid := pub.ec.oid | |||
| buf.WriteByte(byte(len(oid))) | |||
| buf.Write(oid) | |||
| buf.WriteByte(18) // ECDH TYPE | |||
| pub.ecdh.serialize(buf) | |||
| buf.WriteString("Anonymous Sender ") | |||
| buf.Write(pub.Fingerprint[:]) | |||
| return buf.Bytes() | |||
| } | |||
| func decryptKeyECDH(priv *PrivateKey, X, Y *big.Int, C []byte) (out []byte, err error) { | |||
| ecdhpriv, ok := priv.PrivateKey.(*ecdh.PrivateKey) | |||
| if !ok { | |||
| return nil, errors.InvalidArgumentError("bad internal ECDH key") | |||
| } | |||
| Sx := ecdhpriv.DecryptShared(X, Y) | |||
| kdfParams := ECDHKdfParams(&priv.PublicKey) | |||
| hash, ok := s2k.HashIdToHash(byte(priv.ecdh.KdfHash)) | |||
| if !ok { | |||
| return nil, errors.InvalidArgumentError("invalid hash id in private key") | |||
| } | |||
| key := ecdhpriv.KDF(Sx, kdfParams, hash) | |||
| keySize := CipherFunction(priv.ecdh.KdfAlgo).KeySize() | |||
| decrypted, err := ecdh.AESKeyUnwrap(key[:keySize], C) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| // We have to "read ahead" to discover real length of the | |||
| // encryption key and properly unpad buffer. | |||
| cipherFunc := CipherFunction(decrypted[0]) | |||
| // +3 bytes = 1-byte cipher id and checksum 2-byte checksum. | |||
| out = ecdh.UnpadBuffer(decrypted, cipherFunc.KeySize()+3) | |||
| if out == nil { | |||
| return nil, errors.InvalidArgumentError("invalid padding while ECDH") | |||
| } | |||
| return out, nil | |||
| } | |||
| func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *PublicKey, keyBlock []byte) error { | |||
| ecdhpub := pub.PublicKey.(*ecdh.PublicKey) | |||
| kdfParams := ECDHKdfParams(pub) | |||
| hash, ok := s2k.HashIdToHash(byte(pub.ecdh.KdfHash)) | |||
| if !ok { | |||
| return errors.InvalidArgumentError("invalid hash id in private key") | |||
| } | |||
| kdfKeySize := CipherFunction(pub.ecdh.KdfAlgo).KeySize() | |||
| Vx, Vy, C, err := ecdhpub.Encrypt(rand, kdfParams, keyBlock, hash, kdfKeySize) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| mpis, mpiBitLen := ecdh.Marshal(ecdhpub.Curve, Vx, Vy) | |||
| packetLen := len(header) /* header length in bytes */ | |||
| packetLen += 2 /* mpi length in bits */ + len(mpis) | |||
| packetLen += 1 /* ciphertext size in bytes */ + len(C) | |||
| err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| _, err = w.Write(header[:]) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| _, err = w.Write([]byte{byte(mpiBitLen >> 8), byte(mpiBitLen)}) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| _, err = w.Write(mpis[:]) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| w.Write([]byte{byte(len(C))}) | |||
| w.Write(C[:]) | |||
| return nil | |||
| } | |||
| @@ -5,14 +5,15 @@ | |||
| package packet | |||
| import ( | |||
| "crypto/rsa" | |||
| "encoding/binary" | |||
| "io" | |||
| "math/big" | |||
| "strconv" | |||
| "golang.org/x/crypto/openpgp/elgamal" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/ecdh" | |||
| "github.com/keybase/go-crypto/openpgp/elgamal" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/rsa" | |||
| ) | |||
| const encryptedKeyVersion = 3 | |||
| @@ -26,6 +27,7 @@ type EncryptedKey struct { | |||
| Key []byte // only valid after a successful Decrypt | |||
| encryptedMPI1, encryptedMPI2 parsedMPI | |||
| ecdh_C []byte | |||
| } | |||
| func (e *EncryptedKey) parse(r io.Reader) (err error) { | |||
| @@ -48,9 +50,25 @@ func (e *EncryptedKey) parse(r io.Reader) (err error) { | |||
| return | |||
| } | |||
| e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) | |||
| case PubKeyAlgoECDH: | |||
| e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| _, err = readFull(r, buf[:1]) // read C len (1 byte) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| e.ecdh_C = make([]byte, int(buf[0])) | |||
| _, err = readFull(r, e.ecdh_C) | |||
| } | |||
| if err != nil { | |||
| return err | |||
| } | |||
| _, err = consumeAll(r) | |||
| return | |||
| return err | |||
| } | |||
| func checksumKeyMaterial(key []byte) uint16 { | |||
| @@ -77,6 +95,13 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { | |||
| c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) | |||
| c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) | |||
| b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) | |||
| case PubKeyAlgoECDH: | |||
| // Note: Unmarshal checks if point is on the curve. | |||
| c1, c2 := ecdh.Unmarshal(priv.PrivateKey.(*ecdh.PrivateKey).Curve, e.encryptedMPI1.bytes) | |||
| if c1 == nil { | |||
| return errors.InvalidArgumentError("failed to parse EC point for encryption key") | |||
| } | |||
| b, err = decryptKeyECDH(priv, c1, c2, e.ecdh_C) | |||
| default: | |||
| err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) | |||
| } | |||
| @@ -147,6 +172,8 @@ func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunctio | |||
| return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) | |||
| case PubKeyAlgoElGamal: | |||
| return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) | |||
| case PubKeyAlgoECDH: | |||
| return serializeEncryptedKeyECDH(w, config.Random(), buf, pub, keyBlock) | |||
| case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: | |||
| return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) | |||
| } | |||
| @@ -7,10 +7,11 @@ package packet | |||
| import ( | |||
| "crypto" | |||
| "encoding/binary" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "golang.org/x/crypto/openpgp/s2k" | |||
| "io" | |||
| "strconv" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/s2k" | |||
| ) | |||
| // OnePassSignature represents a one-pass signature packet. See RFC 4880, | |||
| @@ -9,7 +9,7 @@ import ( | |||
| "io" | |||
| "io/ioutil" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| ) | |||
| // OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is | |||
| @@ -4,17 +4,19 @@ | |||
| // Package packet implements parsing and serialization of OpenPGP packets, as | |||
| // specified in RFC 4880. | |||
| package packet // import "golang.org/x/crypto/openpgp/packet" | |||
| package packet // import "github.com/keybase/go-crypto/openpgp/packet" | |||
| import ( | |||
| "bufio" | |||
| "crypto/aes" | |||
| "crypto/cipher" | |||
| "crypto/des" | |||
| "golang.org/x/crypto/cast5" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "crypto/elliptic" | |||
| "io" | |||
| "math/big" | |||
| "github.com/keybase/go-crypto/cast5" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| ) | |||
| // readFull is the same as io.ReadFull except that reading zero bytes returns | |||
| @@ -273,6 +275,8 @@ func consumeAll(r io.Reader) (n int64, err error) { | |||
| return | |||
| } | |||
| } | |||
| panic("unreachable") | |||
| } | |||
| // packetType represents the numeric ids of the different OpenPGP packet types. See | |||
| @@ -383,17 +387,18 @@ func Read(r io.Reader) (p Packet, err error) { | |||
| type SignatureType uint8 | |||
| const ( | |||
| SigTypeBinary SignatureType = 0 | |||
| SigTypeText = 1 | |||
| SigTypeGenericCert = 0x10 | |||
| SigTypePersonaCert = 0x11 | |||
| SigTypeCasualCert = 0x12 | |||
| SigTypePositiveCert = 0x13 | |||
| SigTypeSubkeyBinding = 0x18 | |||
| SigTypePrimaryKeyBinding = 0x19 | |||
| SigTypeDirectSignature = 0x1F | |||
| SigTypeKeyRevocation = 0x20 | |||
| SigTypeSubkeyRevocation = 0x28 | |||
| SigTypeBinary SignatureType = 0 | |||
| SigTypeText = 1 | |||
| SigTypeGenericCert = 0x10 | |||
| SigTypePersonaCert = 0x11 | |||
| SigTypeCasualCert = 0x12 | |||
| SigTypePositiveCert = 0x13 | |||
| SigTypeSubkeyBinding = 0x18 | |||
| SigTypePrimaryKeyBinding = 0x19 | |||
| SigTypeDirectSignature = 0x1F | |||
| SigTypeKeyRevocation = 0x20 | |||
| SigTypeSubkeyRevocation = 0x28 | |||
| SigTypeIdentityRevocation = 0x30 | |||
| ) | |||
| // PublicKeyAlgorithm represents the different public key system specified for | |||
| @@ -410,13 +415,15 @@ const ( | |||
| // RFC 6637, Section 5. | |||
| PubKeyAlgoECDH PublicKeyAlgorithm = 18 | |||
| PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | |||
| // RFC -1 | |||
| PubKeyAlgoEdDSA PublicKeyAlgorithm = 22 | |||
| ) | |||
| // CanEncrypt returns true if it's possible to encrypt a message to a public | |||
| // key of the given type. | |||
| func (pka PublicKeyAlgorithm) CanEncrypt() bool { | |||
| switch pka { | |||
| case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal: | |||
| case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH: | |||
| return true | |||
| } | |||
| return false | |||
| @@ -426,7 +433,7 @@ func (pka PublicKeyAlgorithm) CanEncrypt() bool { | |||
| // sign a message. | |||
| func (pka PublicKeyAlgorithm) CanSign() bool { | |||
| switch pka { | |||
| case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: | |||
| case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: | |||
| return true | |||
| } | |||
| return false | |||
| @@ -520,6 +527,25 @@ func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { | |||
| return | |||
| } | |||
| func WritePaddedBigInt(w io.Writer, length int, X *big.Int) (n int, err error) { | |||
| bytes := X.Bytes() | |||
| n1, err := w.Write(make([]byte, length-len(bytes))) | |||
| if err != nil { | |||
| return n1, err | |||
| } | |||
| n2, err := w.Write(bytes) | |||
| if err != nil { | |||
| return n2, err | |||
| } | |||
| return (n1 + n2), err | |||
| } | |||
| // Minimum number of bytes to fit the curve coordinates. All | |||
| // coordinates have to be 0-padded to this length. | |||
| func mpiPointByteLength(curve elliptic.Curve) int { | |||
| return (curve.Params().P.BitLen() + 7) / 8 | |||
| } | |||
| // writeBig serializes a *big.Int to w. | |||
| func writeBig(w io.Writer, i *big.Int) error { | |||
| return writeMPI(w, uint16(i.BitLen()), i.Bytes()) | |||
| @@ -6,21 +6,23 @@ package packet | |||
| import ( | |||
| "bytes" | |||
| "crypto" | |||
| "crypto/cipher" | |||
| "crypto/dsa" | |||
| "crypto/ecdsa" | |||
| "crypto/rsa" | |||
| "crypto/sha1" | |||
| "fmt" | |||
| "io" | |||
| "io/ioutil" | |||
| "math/big" | |||
| "strconv" | |||
| "time" | |||
| "golang.org/x/crypto/openpgp/elgamal" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "golang.org/x/crypto/openpgp/s2k" | |||
| "github.com/keybase/go-crypto/ed25519" | |||
| "github.com/keybase/go-crypto/openpgp/ecdh" | |||
| "github.com/keybase/go-crypto/openpgp/elgamal" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/s2k" | |||
| "github.com/keybase/go-crypto/rsa" | |||
| ) | |||
| // PrivateKey represents a possibly encrypted private key. See RFC 4880, | |||
| @@ -31,9 +33,32 @@ type PrivateKey struct { | |||
| encryptedData []byte | |||
| cipher CipherFunction | |||
| s2k func(out, in []byte) | |||
| PrivateKey interface{} // An *{rsa|dsa|ecdsa}.PrivateKey or a crypto.Signer. | |||
| PrivateKey interface{} // An *rsa.PrivateKey or *dsa.PrivateKey. | |||
| sha1Checksum bool | |||
| iv []byte | |||
| s2kHeader []byte | |||
| } | |||
| type EdDSAPrivateKey struct { | |||
| PrivateKey | |||
| seed parsedMPI | |||
| } | |||
| func (e *EdDSAPrivateKey) Sign(digest []byte) (R, S []byte, err error) { | |||
| r := bytes.NewReader(e.seed.bytes) | |||
| publicKey, privateKey, err := ed25519.GenerateKey(r) | |||
| if err != nil { | |||
| return nil, nil, err | |||
| } | |||
| if !bytes.Equal(publicKey, e.PublicKey.edk.p.bytes[1:]) { // [1:] because [0] is 0x40 mpi header | |||
| return nil, nil, errors.UnsupportedError("EdDSA: Private key does not match public key.") | |||
| } | |||
| sig := ed25519.Sign(privateKey, digest) | |||
| sigLen := ed25519.SignatureSize / 2 | |||
| return sig[:sigLen], sig[sigLen:], nil | |||
| } | |||
| func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey { | |||
| @@ -64,23 +89,6 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK | |||
| return pk | |||
| } | |||
| // NewSignerPrivateKey creates a sign-only PrivateKey from a crypto.Signer that | |||
| // implements RSA or ECDSA. | |||
| func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { | |||
| pk := new(PrivateKey) | |||
| switch pubkey := signer.Public().(type) { | |||
| case rsa.PublicKey: | |||
| pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) | |||
| pk.PubKeyAlgo = PubKeyAlgoRSASignOnly | |||
| case ecdsa.PublicKey: | |||
| pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) | |||
| default: | |||
| panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey") | |||
| } | |||
| pk.PrivateKey = signer | |||
| return pk | |||
| } | |||
| func (pk *PrivateKey) parse(r io.Reader) (err error) { | |||
| err = (&pk.PublicKey).parse(r) | |||
| if err != nil { | |||
| @@ -112,10 +120,16 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) { | |||
| if s2kType == 254 { | |||
| pk.sha1Checksum = true | |||
| } | |||
| // S2K == nil implies that we got a "GNU Dummy" S2K. For instance, | |||
| // because our master secret key is on a USB key in a vault somewhere. | |||
| // In that case, there is no further data to consume here. | |||
| if pk.s2k == nil { | |||
| pk.Encrypted = false | |||
| return | |||
| } | |||
| default: | |||
| return errors.UnsupportedError("deprecated s2k function in private key") | |||
| } | |||
| if pk.Encrypted { | |||
| blockSize := pk.cipher.blockSize() | |||
| if blockSize == 0 { | |||
| @@ -148,31 +162,105 @@ func mod64kHash(d []byte) uint16 { | |||
| return h | |||
| } | |||
| // Encrypt is the counterpart to the Decrypt() method below. It encrypts | |||
| // the private key with the provided passphrase. If config is nil, then | |||
| // the standard, and sensible, defaults apply. | |||
| // | |||
| // A key will be derived from the given passphrase using S2K Specifier | |||
| // Type 3 (Iterated + Salted, see RFC-4880 Sec. 3.7.1.3). This choice | |||
| // is hardcoded in s2k.Serialize(). S2KCount is hardcoded to 0, which is | |||
| // equivalent to 65536. And the hash algorithm for key-derivation can be | |||
| // set with config. The encrypted PrivateKey, using the algorithm specified | |||
| // in config (if provided), is written out to the encryptedData member. | |||
| // When Serialize() is called, this encryptedData member will be | |||
| // serialized, using S2K Usage value of 254, and thus SHA1 checksum. | |||
| func (pk *PrivateKey) Encrypt(passphrase []byte, config *Config) (err error) { | |||
| if pk.PrivateKey == nil { | |||
| return errors.InvalidArgumentError("there is no private key to encrypt") | |||
| } | |||
| pk.sha1Checksum = true | |||
| pk.cipher = config.Cipher() | |||
| s2kConfig := s2k.Config{ | |||
| Hash: config.Hash(), | |||
| S2KCount: 0, | |||
| } | |||
| s2kBuf := bytes.NewBuffer(nil) | |||
| derivedKey := make([]byte, pk.cipher.KeySize()) | |||
| err = s2k.Serialize(s2kBuf, derivedKey, config.Random(), passphrase, &s2kConfig) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| pk.s2kHeader = s2kBuf.Bytes() | |||
| // No good way to set pk.s2k but to call s2k.Parse(), | |||
| // even though we have all the information here, but | |||
| // most of the functions needed are private to s2k. | |||
| pk.s2k, err = s2k.Parse(s2kBuf) | |||
| pk.iv = make([]byte, pk.cipher.blockSize()) | |||
| if _, err = config.Random().Read(pk.iv); err != nil { | |||
| return err | |||
| } | |||
| privateKeyBuf := bytes.NewBuffer(nil) | |||
| if err = pk.serializePrivateKey(privateKeyBuf); err != nil { | |||
| return err | |||
| } | |||
| checksum := sha1.Sum(privateKeyBuf.Bytes()) | |||
| if _, err = privateKeyBuf.Write(checksum[:]); err != nil { | |||
| return err | |||
| } | |||
| pkData := privateKeyBuf.Bytes() | |||
| block := pk.cipher.new(derivedKey) | |||
| pk.encryptedData = make([]byte, len(pkData)) | |||
| cfb := cipher.NewCFBEncrypter(block, pk.iv) | |||
| cfb.XORKeyStream(pk.encryptedData, pkData) | |||
| pk.Encrypted = true | |||
| return nil | |||
| } | |||
| func (pk *PrivateKey) Serialize(w io.Writer) (err error) { | |||
| // TODO(agl): support encrypted private keys | |||
| buf := bytes.NewBuffer(nil) | |||
| err = pk.PublicKey.serializeWithoutHeaders(buf) | |||
| if err != nil { | |||
| return | |||
| } | |||
| buf.WriteByte(0 /* no encryption */) | |||
| privateKeyBuf := bytes.NewBuffer(nil) | |||
| switch priv := pk.PrivateKey.(type) { | |||
| case *rsa.PrivateKey: | |||
| err = serializeRSAPrivateKey(privateKeyBuf, priv) | |||
| case *dsa.PrivateKey: | |||
| err = serializeDSAPrivateKey(privateKeyBuf, priv) | |||
| case *elgamal.PrivateKey: | |||
| err = serializeElGamalPrivateKey(privateKeyBuf, priv) | |||
| case *ecdsa.PrivateKey: | |||
| err = serializeECDSAPrivateKey(privateKeyBuf, priv) | |||
| default: | |||
| err = errors.InvalidArgumentError("unknown private key type") | |||
| } | |||
| if err != nil { | |||
| return | |||
| if pk.PrivateKey == nil { | |||
| _, err = buf.Write([]byte{ | |||
| 254, // SHA-1 Convention | |||
| 9, // Encryption scheme (AES256) | |||
| 101, // GNU Extensions | |||
| 2, // Hash value (SHA1) | |||
| 'G', 'N', 'U', // "GNU" as a string | |||
| 1, // Extension type 1001 (minus 1000) | |||
| }) | |||
| } else if pk.Encrypted { | |||
| _, err = buf.Write([]byte{ | |||
| 254, // SHA-1 Convention | |||
| byte(pk.cipher), // Encryption scheme | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| if _, err = buf.Write(pk.s2kHeader); err != nil { | |||
| return err | |||
| } | |||
| if _, err = buf.Write(pk.iv); err != nil { | |||
| return err | |||
| } | |||
| if _, err = privateKeyBuf.Write(pk.encryptedData); err != nil { | |||
| return err | |||
| } | |||
| } else { | |||
| buf.WriteByte(0 /* no encryption */) | |||
| if err = pk.serializePrivateKey(privateKeyBuf); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| ptype := packetTypePrivateKey | |||
| @@ -181,7 +269,11 @@ func (pk *PrivateKey) Serialize(w io.Writer) (err error) { | |||
| if pk.IsSubkey { | |||
| ptype = packetTypePrivateSubkey | |||
| } | |||
| err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2) | |||
| totalLen := len(contents) + len(privateKeyBytes) | |||
| if !pk.Encrypted { | |||
| totalLen += 2 | |||
| } | |||
| err = serializeHeader(w, ptype, totalLen) | |||
| if err != nil { | |||
| return | |||
| } | |||
| @@ -194,15 +286,38 @@ func (pk *PrivateKey) Serialize(w io.Writer) (err error) { | |||
| return | |||
| } | |||
| checksum := mod64kHash(privateKeyBytes) | |||
| var checksumBytes [2]byte | |||
| checksumBytes[0] = byte(checksum >> 8) | |||
| checksumBytes[1] = byte(checksum) | |||
| _, err = w.Write(checksumBytes[:]) | |||
| if len(privateKeyBytes) > 0 && !pk.Encrypted { | |||
| checksum := mod64kHash(privateKeyBytes) | |||
| var checksumBytes [2]byte | |||
| checksumBytes[0] = byte(checksum >> 8) | |||
| checksumBytes[1] = byte(checksum) | |||
| _, err = w.Write(checksumBytes[:]) | |||
| } | |||
| return | |||
| } | |||
| func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) { | |||
| switch priv := pk.PrivateKey.(type) { | |||
| case *rsa.PrivateKey: | |||
| err = serializeRSAPrivateKey(w, priv) | |||
| case *dsa.PrivateKey: | |||
| err = serializeDSAPrivateKey(w, priv) | |||
| case *elgamal.PrivateKey: | |||
| err = serializeElGamalPrivateKey(w, priv) | |||
| case *ecdsa.PrivateKey: | |||
| err = serializeECDSAPrivateKey(w, priv) | |||
| case *ecdh.PrivateKey: | |||
| err = serializeECDHPrivateKey(w, priv) | |||
| case *EdDSAPrivateKey: | |||
| err = serializeEdDSAPrivateKey(w, priv) | |||
| default: | |||
| err = errors.InvalidArgumentError("unknown private key type") | |||
| } | |||
| return err | |||
| } | |||
| func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error { | |||
| err := writeBig(w, priv.D) | |||
| if err != nil { | |||
| @@ -231,11 +346,23 @@ func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error { | |||
| return writeBig(w, priv.D) | |||
| } | |||
| func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error { | |||
| return writeBig(w, priv.X) | |||
| } | |||
| func serializeEdDSAPrivateKey(w io.Writer, priv *EdDSAPrivateKey) error { | |||
| return writeMPI(w, priv.seed.bitLength, priv.seed.bytes) | |||
| } | |||
| // Decrypt decrypts an encrypted private key using a passphrase. | |||
| func (pk *PrivateKey) Decrypt(passphrase []byte) error { | |||
| if !pk.Encrypted { | |||
| return nil | |||
| } | |||
| // For GNU Dummy S2K, there's no key here, so don't do anything. | |||
| if pk.s2k == nil { | |||
| return nil | |||
| } | |||
| key := make([]byte, pk.cipher.KeySize()) | |||
| pk.s2k(key, passphrase) | |||
| @@ -284,6 +411,10 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) { | |||
| return pk.parseElGamalPrivateKey(data) | |||
| case PubKeyAlgoECDSA: | |||
| return pk.parseECDSAPrivateKey(data) | |||
| case PubKeyAlgoECDH: | |||
| return pk.parseECDHPrivateKey(data) | |||
| case PubKeyAlgoEdDSA: | |||
| return pk.parseEdDSAPrivateKey(data) | |||
| } | |||
| panic("impossible") | |||
| } | |||
| @@ -360,8 +491,28 @@ func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) { | |||
| return nil | |||
| } | |||
| func (pk *PrivateKey) parseECDHPrivateKey(data []byte) (err error) { | |||
| pub := pk.PublicKey.PublicKey.(*ecdh.PublicKey) | |||
| priv := new(ecdh.PrivateKey) | |||
| priv.PublicKey = *pub | |||
| buf := bytes.NewBuffer(data) | |||
| d, _, err := readMPI(buf) | |||
| if err != nil { | |||
| return | |||
| } | |||
| priv.X = new(big.Int).SetBytes(d) | |||
| pk.PrivateKey = priv | |||
| pk.Encrypted = false | |||
| pk.encryptedData = nil | |||
| return nil | |||
| } | |||
| func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) { | |||
| ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey) | |||
| ecdsaPriv := new(ecdsa.PrivateKey) | |||
| ecdsaPriv.PublicKey = *ecdsaPub | |||
| buf := bytes.NewBuffer(data) | |||
| d, _, err := readMPI(buf) | |||
| @@ -369,10 +520,29 @@ func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) { | |||
| return | |||
| } | |||
| pk.PrivateKey = &ecdsa.PrivateKey{ | |||
| PublicKey: *ecdsaPub, | |||
| D: new(big.Int).SetBytes(d), | |||
| ecdsaPriv.D = new(big.Int).SetBytes(d) | |||
| pk.PrivateKey = ecdsaPriv | |||
| pk.Encrypted = false | |||
| pk.encryptedData = nil | |||
| return nil | |||
| } | |||
| func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) { | |||
| eddsaPriv := new(EdDSAPrivateKey) | |||
| eddsaPriv.PublicKey = pk.PublicKey | |||
| buf := bytes.NewBuffer(data) | |||
| eddsaPriv.seed.bytes, eddsaPriv.seed.bitLength, err = readMPI(buf) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| if bLen := len(eddsaPriv.seed.bytes); bLen != 32 { // 32 bytes private part of ed25519 key. | |||
| return errors.UnsupportedError(fmt.Sprintf("Unexpected EdDSA private key length: %d", bLen)) | |||
| } | |||
| pk.PrivateKey = eddsaPriv | |||
| pk.Encrypted = false | |||
| pk.encryptedData = nil | |||
| @@ -10,7 +10,6 @@ import ( | |||
| "crypto/dsa" | |||
| "crypto/ecdsa" | |||
| "crypto/elliptic" | |||
| "crypto/rsa" | |||
| "crypto/sha1" | |||
| _ "crypto/sha256" | |||
| _ "crypto/sha512" | |||
| @@ -22,8 +21,13 @@ import ( | |||
| "strconv" | |||
| "time" | |||
| "golang.org/x/crypto/openpgp/elgamal" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/brainpool" | |||
| "github.com/keybase/go-crypto/curve25519" | |||
| "github.com/keybase/go-crypto/ed25519" | |||
| "github.com/keybase/go-crypto/openpgp/ecdh" | |||
| "github.com/keybase/go-crypto/openpgp/elgamal" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/rsa" | |||
| ) | |||
| var ( | |||
| @@ -33,9 +37,19 @@ var ( | |||
| oidCurveP384 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x22} | |||
| // NIST curve P-521 | |||
| oidCurveP521 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x23} | |||
| // Brainpool curve P-256r1 | |||
| oidCurveP256r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07} | |||
| // Brainpool curve P-384r1 | |||
| oidCurveP384r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B} | |||
| // Brainpool curve P-512r1 | |||
| oidCurveP512r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D} | |||
| // EdDSA | |||
| oidEdDSA []byte = []byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01} | |||
| // cv25519 | |||
| oidCurve25519 []byte = []byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01} | |||
| ) | |||
| const maxOIDLength = 8 | |||
| const maxOIDLength = 10 | |||
| // ecdsaKey stores the algorithm-specific fields for ECDSA keys. | |||
| // as defined in RFC 6637, Section 9. | |||
| @@ -46,6 +60,38 @@ type ecdsaKey struct { | |||
| p parsedMPI | |||
| } | |||
| type edDSAkey struct { | |||
| ecdsaKey | |||
| } | |||
| func copyFrontFill(dst, src []byte, length int) int { | |||
| if srcLen := len(src); srcLen < length { | |||
| return copy(dst[length-srcLen:], src[:]) | |||
| } else { | |||
| return copy(dst[:], src[:]) | |||
| } | |||
| } | |||
| func (e *edDSAkey) Verify(payload []byte, r parsedMPI, s parsedMPI) bool { | |||
| const halfSigSize = ed25519.SignatureSize / 2 | |||
| var sig [ed25519.SignatureSize]byte | |||
| // NOTE: The first byte is 0x40 - MPI header | |||
| // TODO: Maybe clean the code up and use 0x40 as a header when | |||
| // reading and keep only actual number in p field. Find out how | |||
| // other MPIs are stored. | |||
| key := e.p.bytes[1:] | |||
| // Note: it may happen that R + S do not form 64-byte signature buffer that | |||
| // ed25519 expects, but because we copy it over to an array of exact size, | |||
| // we will always pass correctly sized slice to Verify. Slice too short | |||
| // would make ed25519 panic(). | |||
| copyFrontFill(sig[:halfSigSize], r.bytes, halfSigSize) | |||
| copyFrontFill(sig[halfSigSize:], s.bytes, halfSigSize) | |||
| return ed25519.Verify(key, payload, sig[:]) | |||
| } | |||
| // parseOID reads the OID for the curve as defined in RFC 6637, Section 9. | |||
| func parseOID(r io.Reader) (oid []byte, err error) { | |||
| buf := make([]byte, maxOIDLength) | |||
| @@ -67,7 +113,7 @@ func (f *ecdsaKey) parse(r io.Reader) (err error) { | |||
| return err | |||
| } | |||
| f.p.bytes, f.p.bitLength, err = readMPI(r) | |||
| return | |||
| return err | |||
| } | |||
| func (f *ecdsaKey) serialize(w io.Writer) (err error) { | |||
| @@ -80,17 +126,34 @@ func (f *ecdsaKey) serialize(w io.Writer) (err error) { | |||
| return writeMPIs(w, f.p) | |||
| } | |||
| func getCurveByOid(oid []byte) elliptic.Curve { | |||
| switch { | |||
| case bytes.Equal(oid, oidCurveP256): | |||
| return elliptic.P256() | |||
| case bytes.Equal(oid, oidCurveP384): | |||
| return elliptic.P384() | |||
| case bytes.Equal(oid, oidCurveP521): | |||
| return elliptic.P521() | |||
| case bytes.Equal(oid, oidCurveP256r1): | |||
| return brainpool.P256r1() | |||
| case bytes.Equal(oid, oidCurveP384r1): | |||
| return brainpool.P384r1() | |||
| case bytes.Equal(oid, oidCurveP512r1): | |||
| return brainpool.P512r1() | |||
| case bytes.Equal(oid, oidCurve25519): | |||
| return curve25519.Cv25519() | |||
| default: | |||
| return nil | |||
| } | |||
| } | |||
| func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) { | |||
| var c elliptic.Curve | |||
| if bytes.Equal(f.oid, oidCurveP256) { | |||
| c = elliptic.P256() | |||
| } else if bytes.Equal(f.oid, oidCurveP384) { | |||
| c = elliptic.P384() | |||
| } else if bytes.Equal(f.oid, oidCurveP521) { | |||
| c = elliptic.P521() | |||
| } else { | |||
| var c = getCurveByOid(f.oid) | |||
| // Curve25519 should not be used in ECDSA. | |||
| if c == nil || bytes.Equal(f.oid, oidCurve25519) { | |||
| return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid)) | |||
| } | |||
| // Note: Unmarshal already checks if point is on curve. | |||
| x, y := elliptic.Unmarshal(c, f.p.bytes) | |||
| if x == nil { | |||
| return nil, errors.UnsupportedError("failed to parse EC point") | |||
| @@ -98,6 +161,20 @@ func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) { | |||
| return &ecdsa.PublicKey{Curve: c, X: x, Y: y}, nil | |||
| } | |||
| func (f *ecdsaKey) newECDH() (*ecdh.PublicKey, error) { | |||
| var c = getCurveByOid(f.oid) | |||
| if c == nil { | |||
| return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid)) | |||
| } | |||
| // ecdh.Unmarshal handles unmarshaling for all curve types. It | |||
| // also checks if point is on curve. | |||
| x, y := ecdh.Unmarshal(c, f.p.bytes) | |||
| if x == nil { | |||
| return nil, errors.UnsupportedError("failed to parse EC point") | |||
| } | |||
| return &ecdh.PublicKey{Curve: c, X: x, Y: y}, nil | |||
| } | |||
| func (f *ecdsaKey) byteLen() int { | |||
| return 1 + len(f.oid) + 2 + len(f.p.bytes) | |||
| } | |||
| @@ -163,6 +240,9 @@ type PublicKey struct { | |||
| // RFC 6637 fields | |||
| ec *ecdsaKey | |||
| ecdh *ecdhKdf | |||
| // EdDSA fields (no RFC available), uses ecdsa scaffolding | |||
| edk *edDSAkey | |||
| } | |||
| // signingKey provides a convenient abstraction over signature verification | |||
| @@ -172,21 +252,28 @@ type signingKey interface { | |||
| serializeWithoutHeaders(io.Writer) error | |||
| } | |||
| func fromBig(n *big.Int) parsedMPI { | |||
| func FromBig(n *big.Int) parsedMPI { | |||
| return parsedMPI{ | |||
| bytes: n.Bytes(), | |||
| bitLength: uint16(n.BitLen()), | |||
| } | |||
| } | |||
| func FromBytes(bytes []byte) parsedMPI { | |||
| return parsedMPI{ | |||
| bytes: bytes, | |||
| bitLength: uint16(8 * len(bytes)), | |||
| } | |||
| } | |||
| // NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey. | |||
| func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey { | |||
| pk := &PublicKey{ | |||
| CreationTime: creationTime, | |||
| PubKeyAlgo: PubKeyAlgoRSA, | |||
| PublicKey: pub, | |||
| n: fromBig(pub.N), | |||
| e: fromBig(big.NewInt(int64(pub.E))), | |||
| n: FromBig(pub.N), | |||
| e: FromBig(big.NewInt(int64(pub.E))), | |||
| } | |||
| pk.setFingerPrintAndKeyId() | |||
| @@ -199,25 +286,38 @@ func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey { | |||
| CreationTime: creationTime, | |||
| PubKeyAlgo: PubKeyAlgoDSA, | |||
| PublicKey: pub, | |||
| p: fromBig(pub.P), | |||
| q: fromBig(pub.Q), | |||
| g: fromBig(pub.G), | |||
| y: fromBig(pub.Y), | |||
| p: FromBig(pub.P), | |||
| q: FromBig(pub.Q), | |||
| g: FromBig(pub.G), | |||
| y: FromBig(pub.Y), | |||
| } | |||
| pk.setFingerPrintAndKeyId() | |||
| return pk | |||
| } | |||
| // check EdDSA public key material. | |||
| // There is currently no RFC for it, but it doesn't mean it's not | |||
| // implemented or in use. | |||
| func (e *edDSAkey) check() error { | |||
| if !bytes.Equal(e.oid, oidEdDSA) { | |||
| return errors.UnsupportedError(fmt.Sprintf("Bad OID for EdDSA key: %v", e.oid)) | |||
| } | |||
| if bLen := len(e.p.bytes); bLen != 33 { // 32 bytes for ed25519 key and 1 byte for 0x40 header | |||
| return errors.UnsupportedError(fmt.Sprintf("Unexpected EdDSA public key length: %d", bLen)) | |||
| } | |||
| return nil | |||
| } | |||
| // NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey. | |||
| func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey { | |||
| pk := &PublicKey{ | |||
| CreationTime: creationTime, | |||
| PubKeyAlgo: PubKeyAlgoElGamal, | |||
| PublicKey: pub, | |||
| p: fromBig(pub.P), | |||
| g: fromBig(pub.G), | |||
| y: fromBig(pub.Y), | |||
| p: FromBig(pub.P), | |||
| g: FromBig(pub.G), | |||
| y: FromBig(pub.Y), | |||
| } | |||
| pk.setFingerPrintAndKeyId() | |||
| @@ -231,7 +331,6 @@ func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey | |||
| PublicKey: pub, | |||
| ec: new(ecdsaKey), | |||
| } | |||
| switch pub.Curve { | |||
| case elliptic.P256(): | |||
| pk.ec.oid = oidCurveP256 | |||
| @@ -239,10 +338,13 @@ func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey | |||
| pk.ec.oid = oidCurveP384 | |||
| case elliptic.P521(): | |||
| pk.ec.oid = oidCurveP521 | |||
| default: | |||
| panic("unknown elliptic curve") | |||
| case brainpool.P256r1(): | |||
| pk.ec.oid = oidCurveP256r1 | |||
| case brainpool.P384r1(): | |||
| pk.ec.oid = oidCurveP384r1 | |||
| case brainpool.P512r1(): | |||
| pk.ec.oid = oidCurveP512r1 | |||
| } | |||
| pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) | |||
| pk.ec.p.bitLength = uint16(8 * len(pk.ec.p.bytes)) | |||
| @@ -269,6 +371,12 @@ func (pk *PublicKey) parse(r io.Reader) (err error) { | |||
| err = pk.parseDSA(r) | |||
| case PubKeyAlgoElGamal: | |||
| err = pk.parseElGamal(r) | |||
| case PubKeyAlgoEdDSA: | |||
| pk.edk = new(edDSAkey) | |||
| if err = pk.edk.parse(r); err != nil { | |||
| return err | |||
| } | |||
| err = pk.edk.check() | |||
| case PubKeyAlgoECDSA: | |||
| pk.ec = new(ecdsaKey) | |||
| if err = pk.ec.parse(r); err != nil { | |||
| @@ -284,8 +392,7 @@ func (pk *PublicKey) parse(r io.Reader) (err error) { | |||
| if err = pk.ecdh.parse(r); err != nil { | |||
| return | |||
| } | |||
| // The ECDH key is stored in an ecdsa.PublicKey for convenience. | |||
| pk.PublicKey, err = pk.ec.newECDSA() | |||
| pk.PublicKey, err = pk.ec.newECDH() | |||
| default: | |||
| err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) | |||
| } | |||
| @@ -318,7 +425,7 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err error) { | |||
| return | |||
| } | |||
| if len(pk.e.bytes) > 3 { | |||
| if len(pk.e.bytes) > 7 { | |||
| err = errors.UnsupportedError("large public exponent") | |||
| return | |||
| } | |||
| @@ -328,7 +435,7 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err error) { | |||
| } | |||
| for i := 0; i < len(pk.e.bytes); i++ { | |||
| rsa.E <<= 8 | |||
| rsa.E |= int(pk.e.bytes[i]) | |||
| rsa.E |= int64(pk.e.bytes[i]) | |||
| } | |||
| pk.PublicKey = rsa | |||
| return | |||
| @@ -410,6 +517,8 @@ func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) { | |||
| case PubKeyAlgoECDH: | |||
| pLength += uint16(pk.ec.byteLen()) | |||
| pLength += uint16(pk.ecdh.byteLen()) | |||
| case PubKeyAlgoEdDSA: | |||
| pLength += uint16(pk.edk.byteLen()) | |||
| default: | |||
| panic("unknown public key algorithm") | |||
| } | |||
| @@ -439,6 +548,8 @@ func (pk *PublicKey) Serialize(w io.Writer) (err error) { | |||
| case PubKeyAlgoECDH: | |||
| length += pk.ec.byteLen() | |||
| length += pk.ecdh.byteLen() | |||
| case PubKeyAlgoEdDSA: | |||
| length += pk.edk.byteLen() | |||
| default: | |||
| panic("unknown public key algorithm") | |||
| } | |||
| @@ -480,6 +591,8 @@ func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) { | |||
| return writeMPIs(w, pk.p, pk.g, pk.y) | |||
| case PubKeyAlgoECDSA: | |||
| return pk.ec.serialize(w) | |||
| case PubKeyAlgoEdDSA: | |||
| return pk.edk.serialize(w) | |||
| case PubKeyAlgoECDH: | |||
| if err = pk.ec.serialize(w); err != nil { | |||
| return | |||
| @@ -504,9 +617,18 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro | |||
| signed.Write(sig.HashSuffix) | |||
| hashBytes := signed.Sum(nil) | |||
| if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { | |||
| return errors.SignatureError("hash tag doesn't match") | |||
| } | |||
| // NOTE(maxtaco) 2016-08-22 | |||
| // | |||
| // We used to do this: | |||
| // | |||
| // if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { | |||
| // return errors.SignatureError("hash tag doesn't match") | |||
| // } | |||
| // | |||
| // But don't do anything in this case. Some GPGs generate bad | |||
| // 2-byte hash prefixes, but GPG also doesn't seem to care on | |||
| // import. See BrentMaxwell's key. I think it's safe to disable | |||
| // this check! | |||
| if pk.PubKeyAlgo != sig.PubKeyAlgo { | |||
| return errors.InvalidArgumentError("public key and signature use different algorithms") | |||
| @@ -537,9 +659,15 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro | |||
| return errors.SignatureError("ECDSA verification failure") | |||
| } | |||
| return nil | |||
| case PubKeyAlgoEdDSA: | |||
| if !pk.edk.Verify(hashBytes, sig.EdDSASigR, sig.EdDSASigS) { | |||
| return errors.SignatureError("EdDSA verification failure") | |||
| } | |||
| return nil | |||
| default: | |||
| return errors.SignatureError("Unsupported public key algorithm used in signature") | |||
| } | |||
| panic("unreachable") | |||
| } | |||
| // VerifySignatureV3 returns nil iff sig is a valid signature, made by this | |||
| @@ -584,6 +712,7 @@ func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err | |||
| default: | |||
| panic("shouldn't happen") | |||
| } | |||
| panic("unreachable") | |||
| } | |||
| // keySignatureHash returns a Hash of the message that needs to be signed for | |||
| @@ -594,12 +723,18 @@ func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, | |||
| } | |||
| h = hashFunc.New() | |||
| updateKeySignatureHash(pk, signed, h) | |||
| return | |||
| } | |||
| // updateKeySignatureHash does the actual hash updates for keySignatureHash. | |||
| func updateKeySignatureHash(pk, signed signingKey, h hash.Hash) { | |||
| // RFC 4880, section 5.2.4 | |||
| pk.SerializeSignaturePrefix(h) | |||
| pk.serializeWithoutHeaders(h) | |||
| signed.SerializeSignaturePrefix(h) | |||
| signed.serializeWithoutHeaders(h) | |||
| return | |||
| } | |||
| // VerifyKeySignature returns nil iff sig is a valid signature, made by this | |||
| @@ -614,6 +749,19 @@ func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error | |||
| } | |||
| if sig.FlagSign { | |||
| // BUG(maxtaco) | |||
| // | |||
| // We should check for more than FlagsSign here, because if | |||
| // you read keys.go, we can sometimes use signing subkeys even if they're | |||
| // not explicitly flagged as such. However, so doing fails lots of currently | |||
| // working tests, so I'm not going to do much here. | |||
| // | |||
| // In other words, we should have this disjunction in the condition above: | |||
| // | |||
| // || (!sig.FlagsValid && pk.PubKeyAlgo.CanSign()) { | |||
| // | |||
| // Signing subkeys must be cross-signed. See | |||
| // https://www.gnupg.org/faq/subkey-cross-certify.html. | |||
| if sig.EmbeddedSignature == nil { | |||
| @@ -648,14 +796,27 @@ func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err er | |||
| // VerifyRevocationSignature returns nil iff sig is a valid signature, made by this | |||
| // public key. | |||
| func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) { | |||
| h, err := keyRevocationHash(pk, sig.Hash) | |||
| func (pk *PublicKey) VerifyRevocationSignature(revokedKey *PublicKey, sig *Signature) (err error) { | |||
| h, err := keyRevocationHash(revokedKey, sig.Hash) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| return pk.VerifySignature(h, sig) | |||
| } | |||
| type teeHash struct { | |||
| h hash.Hash | |||
| } | |||
| func (t teeHash) Write(b []byte) (n int, err error) { | |||
| fmt.Printf("hash -> %s %+v\n", string(b), b) | |||
| return t.h.Write(b) | |||
| } | |||
| func (t teeHash) Sum(b []byte) []byte { return t.h.Sum(b) } | |||
| func (t teeHash) Reset() { t.h.Reset() } | |||
| func (t teeHash) Size() int { return t.h.Size() } | |||
| func (t teeHash) BlockSize() int { return t.h.BlockSize() } | |||
| // userIdSignatureHash returns a Hash of the message that needs to be signed | |||
| // to assert that pk is a valid key for id. | |||
| func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) { | |||
| @@ -664,6 +825,14 @@ func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash | |||
| } | |||
| h = hashFunc.New() | |||
| updateUserIdSignatureHash(id, pk, h) | |||
| return | |||
| } | |||
| // updateUserIdSignatureHash does the actual hash updates for | |||
| // userIdSignatureHash. | |||
| func updateUserIdSignatureHash(id string, pk *PublicKey, h hash.Hash) { | |||
| // RFC 4880, section 5.2.4 | |||
| pk.SerializeSignaturePrefix(h) | |||
| pk.serializeWithoutHeaders(h) | |||
| @@ -732,7 +901,9 @@ func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) { | |||
| return | |||
| } | |||
| // BitLength returns the bit length for the given public key. | |||
| // BitLength returns the bit length for the given public key. Used for | |||
| // displaying key information, actual buffers and BigInts inside may | |||
| // have non-matching different size if the key is invalid. | |||
| func (pk *PublicKey) BitLength() (bitLength uint16, err error) { | |||
| switch pk.PubKeyAlgo { | |||
| case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | |||
| @@ -741,6 +912,17 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) { | |||
| bitLength = pk.p.bitLength | |||
| case PubKeyAlgoElGamal: | |||
| bitLength = pk.p.bitLength | |||
| case PubKeyAlgoECDH: | |||
| ecdhPublicKey := pk.PublicKey.(*ecdh.PublicKey) | |||
| bitLength = uint16(ecdhPublicKey.Curve.Params().BitSize) | |||
| case PubKeyAlgoECDSA: | |||
| ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey) | |||
| bitLength = uint16(ecdsaPublicKey.Curve.Params().BitSize) | |||
| case PubKeyAlgoEdDSA: | |||
| // EdDSA only support ed25519 curves right now, just return | |||
| // the length. Also, we don't have any PublicKey.Curve object | |||
| // to look the size up from. | |||
| bitLength = 256 | |||
| default: | |||
| err = errors.InvalidArgumentError("bad public-key algorithm") | |||
| } | |||
| @@ -7,7 +7,6 @@ package packet | |||
| import ( | |||
| "crypto" | |||
| "crypto/md5" | |||
| "crypto/rsa" | |||
| "encoding/binary" | |||
| "fmt" | |||
| "hash" | |||
| @@ -16,7 +15,8 @@ import ( | |||
| "strconv" | |||
| "time" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/rsa" | |||
| ) | |||
| // PublicKeyV3 represents older, version 3 public keys. These keys are less secure and | |||
| @@ -42,8 +42,8 @@ func newRSAPublicKeyV3(creationTime time.Time, pub *rsa.PublicKey) *PublicKeyV3 | |||
| pk := &PublicKeyV3{ | |||
| CreationTime: creationTime, | |||
| PublicKey: pub, | |||
| n: fromBig(pub.N), | |||
| e: fromBig(big.NewInt(int64(pub.E))), | |||
| n: FromBig(pub.N), | |||
| e: FromBig(big.NewInt(int64(pub.E))), | |||
| } | |||
| pk.setFingerPrintAndKeyId() | |||
| @@ -100,14 +100,14 @@ func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) { | |||
| if len(pk.n.bytes) < 8 { | |||
| return errors.StructuralError("v3 public key modulus is too short") | |||
| } | |||
| if len(pk.e.bytes) > 3 { | |||
| if len(pk.e.bytes) > 7 { | |||
| err = errors.UnsupportedError("large public exponent") | |||
| return | |||
| } | |||
| rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)} | |||
| for i := 0; i < len(pk.e.bytes); i++ { | |||
| rsa.E <<= 8 | |||
| rsa.E |= int(pk.e.bytes[i]) | |||
| rsa.E |= int64(pk.e.bytes[i]) | |||
| } | |||
| pk.PublicKey = rsa | |||
| return | |||
| @@ -216,6 +216,7 @@ func (pk *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (er | |||
| // V3 public keys only support RSA. | |||
| panic("shouldn't happen") | |||
| } | |||
| panic("unreachable") | |||
| } | |||
| // VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this | |||
| @@ -5,8 +5,9 @@ | |||
| package packet | |||
| import ( | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "io" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| ) | |||
| // Reader reads packets from an io.Reader and allows packets to be 'unread' so | |||
| @@ -46,7 +47,6 @@ func (r *Reader) Next() (p Packet, err error) { | |||
| return nil, err | |||
| } | |||
| } | |||
| return nil, io.EOF | |||
| } | |||
| @@ -9,16 +9,15 @@ import ( | |||
| "crypto" | |||
| "crypto/dsa" | |||
| "crypto/ecdsa" | |||
| "encoding/asn1" | |||
| "encoding/binary" | |||
| "hash" | |||
| "io" | |||
| "math/big" | |||
| "strconv" | |||
| "time" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "golang.org/x/crypto/openpgp/s2k" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/s2k" | |||
| "github.com/keybase/go-crypto/rsa" | |||
| ) | |||
| const ( | |||
| @@ -29,6 +28,29 @@ const ( | |||
| KeyFlagEncryptStorage | |||
| ) | |||
| // Signer can be implemented by application code to do actual signing. | |||
| type Signer interface { | |||
| hash.Hash | |||
| Sign(sig *Signature) error | |||
| KeyId() uint64 | |||
| PublicKeyAlgo() PublicKeyAlgorithm | |||
| } | |||
| // RevocationKey represents designated revoker packet. See RFC 4880 | |||
| // section 5.2.3.15 for details. | |||
| type RevocationKey struct { | |||
| Class byte | |||
| PublicKeyAlgo PublicKeyAlgorithm | |||
| Fingerprint []byte | |||
| } | |||
| // KeyFlagBits holds boolean whether any usage flags were provided in | |||
| // the signature and BitField with KeyFlag* flags. | |||
| type KeyFlagBits struct { | |||
| Valid bool | |||
| BitField byte | |||
| } | |||
| // Signature represents a signature. See RFC 4880, section 5.2. | |||
| type Signature struct { | |||
| SigType SignatureType | |||
| @@ -45,6 +67,7 @@ type Signature struct { | |||
| RSASignature parsedMPI | |||
| DSASigR, DSASigS parsedMPI | |||
| ECDSASigR, ECDSASigS parsedMPI | |||
| EdDSASigR, EdDSASigS parsedMPI | |||
| // rawSubpackets contains the unparsed subpackets, in order. | |||
| rawSubpackets []outputSubpacket | |||
| @@ -54,8 +77,10 @@ type Signature struct { | |||
| SigLifetimeSecs, KeyLifetimeSecs *uint32 | |||
| PreferredSymmetric, PreferredHash, PreferredCompression []uint8 | |||
| PreferredKeyServer string | |||
| IssuerKeyId *uint64 | |||
| IsPrimaryId *bool | |||
| IssuerFingerprint []byte | |||
| // FlagsValid is set if any flags were given. See RFC 4880, section | |||
| // 5.2.3.21 for details. | |||
| @@ -67,6 +92,12 @@ type Signature struct { | |||
| RevocationReason *uint8 | |||
| RevocationReasonText string | |||
| // PolicyURI is optional. See RFC 4880, Section 5.2.3.20 for details | |||
| PolicyURI string | |||
| // Regex is a regex that can match a PGP UID. See RFC 4880, 5.2.3.14 for details | |||
| Regex string | |||
| // MDC is set if this signature has a feature packet that indicates | |||
| // support for MDC subpackets. | |||
| MDC bool | |||
| @@ -76,6 +107,16 @@ type Signature struct { | |||
| // subkey as their own. | |||
| EmbeddedSignature *Signature | |||
| // StubbedOutCriticalError is not fail-stop, since it shouldn't break key parsing | |||
| // when appearing in WoT-style cross signatures. But it should prevent a signature | |||
| // from being applied to a primary or subkey. | |||
| StubbedOutCriticalError error | |||
| // DesignaterRevoker will be present if this signature certifies a | |||
| // designated revoking key id (3rd party key that can sign | |||
| // revocation for this key). | |||
| DesignatedRevoker *RevocationKey | |||
| outSubpackets []outputSubpacket | |||
| } | |||
| @@ -98,7 +139,7 @@ func (sig *Signature) parse(r io.Reader) (err error) { | |||
| sig.SigType = SignatureType(buf[0]) | |||
| sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) | |||
| switch sig.PubKeyAlgo { | |||
| case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: | |||
| case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: | |||
| default: | |||
| err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) | |||
| return | |||
| @@ -162,6 +203,11 @@ func (sig *Signature) parse(r io.Reader) (err error) { | |||
| if err == nil { | |||
| sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) | |||
| } | |||
| case PubKeyAlgoEdDSA: | |||
| sig.EdDSASigR.bytes, sig.EdDSASigR.bitLength, err = readMPI(r) | |||
| if err == nil { | |||
| sig.EdDSASigS.bytes, sig.EdDSASigS.bitLength, err = readMPI(r) | |||
| } | |||
| case PubKeyAlgoECDSA: | |||
| sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r) | |||
| if err == nil { | |||
| @@ -195,16 +241,21 @@ type signatureSubpacketType uint8 | |||
| const ( | |||
| creationTimeSubpacket signatureSubpacketType = 2 | |||
| signatureExpirationSubpacket signatureSubpacketType = 3 | |||
| regularExpressionSubpacket signatureSubpacketType = 6 | |||
| keyExpirationSubpacket signatureSubpacketType = 9 | |||
| prefSymmetricAlgosSubpacket signatureSubpacketType = 11 | |||
| revocationKey signatureSubpacketType = 12 | |||
| issuerSubpacket signatureSubpacketType = 16 | |||
| prefHashAlgosSubpacket signatureSubpacketType = 21 | |||
| prefCompressionSubpacket signatureSubpacketType = 22 | |||
| prefKeyServerSubpacket signatureSubpacketType = 24 | |||
| primaryUserIdSubpacket signatureSubpacketType = 25 | |||
| policyURISubpacket signatureSubpacketType = 26 | |||
| keyFlagsSubpacket signatureSubpacketType = 27 | |||
| reasonForRevocationSubpacket signatureSubpacketType = 29 | |||
| featuresSubpacket signatureSubpacketType = 30 | |||
| embeddedSignatureSubpacket signatureSubpacketType = 32 | |||
| issuerFingerprint signatureSubpacketType = 33 | |||
| ) | |||
| // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. | |||
| @@ -382,6 +433,32 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r | |||
| if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { | |||
| return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) | |||
| } | |||
| case policyURISubpacket: | |||
| // See RFC 4880, Section 5.2.3.20 | |||
| sig.PolicyURI = string(subpacket[:]) | |||
| case regularExpressionSubpacket: | |||
| sig.Regex = string(subpacket[:]) | |||
| if isCritical { | |||
| sig.StubbedOutCriticalError = errors.UnsupportedError("regex support is stubbed out") | |||
| } | |||
| case prefKeyServerSubpacket: | |||
| sig.PreferredKeyServer = string(subpacket[:]) | |||
| case issuerFingerprint: | |||
| // The first byte is how many bytes the fingerprint is, but we'll just | |||
| // read until the end of the subpacket, so we'll ignore it. | |||
| sig.IssuerFingerprint = append([]byte{}, subpacket[1:]...) | |||
| case revocationKey: | |||
| // Authorizes the specified key to issue revocation signatures | |||
| // for a key. | |||
| // TODO: Class octet must have bit 0x80 set. If the bit 0x40 | |||
| // is set, then this means that the revocation information is | |||
| // sensitive. | |||
| sig.DesignatedRevoker = &RevocationKey{ | |||
| Class: subpacket[0], | |||
| PublicKeyAlgo: PublicKeyAlgorithm(subpacket[1]), | |||
| Fingerprint: append([]byte{}, subpacket[2:]...), | |||
| } | |||
| default: | |||
| if isCritical { | |||
| err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) | |||
| @@ -464,6 +541,26 @@ func (sig *Signature) KeyExpired(currentTime time.Time) bool { | |||
| return currentTime.After(expiry) | |||
| } | |||
| // ExpiresBeforeOther checks if other signature has expiration at | |||
| // later date than sig. | |||
| func (sig *Signature) ExpiresBeforeOther(other *Signature) bool { | |||
| if sig.KeyLifetimeSecs == nil { | |||
| // This sig never expires, or has infinitely long expiration | |||
| // time. | |||
| return false | |||
| } else if other.KeyLifetimeSecs == nil { | |||
| // This sig expires at some non-infinite point, but the other | |||
| // sig never expires. | |||
| return true | |||
| } | |||
| getExpiryDate := func(s *Signature) time.Time { | |||
| return s.CreationTime.Add(time.Duration(*s.KeyLifetimeSecs) * time.Second) | |||
| } | |||
| return getExpiryDate(other).After(getExpiryDate(sig)) | |||
| } | |||
| // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. | |||
| func (sig *Signature) buildHashSuffix() (err error) { | |||
| hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) | |||
| @@ -509,16 +606,27 @@ func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { | |||
| // On success, the signature is stored in sig. Call Serialize to write it out. | |||
| // If config is nil, sensible defaults will be used. | |||
| func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { | |||
| signer, hashIsSigner := h.(Signer) | |||
| if !hashIsSigner && (priv == nil || priv.PrivateKey == nil) { | |||
| err = errors.InvalidArgumentError("attempting to sign with nil PrivateKey") | |||
| return | |||
| } | |||
| sig.outSubpackets = sig.buildSubpackets() | |||
| digest, err := sig.signPrepareHash(h) | |||
| if err != nil { | |||
| return | |||
| } | |||
| if hashIsSigner { | |||
| err = signer.Sign(sig) | |||
| return | |||
| } | |||
| switch priv.PubKeyAlgo { | |||
| case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | |||
| // supports both *rsa.PrivateKey and crypto.Signer | |||
| sig.RSASignature.bytes, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | |||
| sig.RSASignature.bytes, err = rsa.SignPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest) | |||
| sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes)) | |||
| case PubKeyAlgoDSA: | |||
| dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) | |||
| @@ -536,20 +644,16 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e | |||
| sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) | |||
| } | |||
| case PubKeyAlgoECDSA: | |||
| var r, s *big.Int | |||
| if pk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok { | |||
| // direct support, avoid asn1 wrapping/unwrapping | |||
| r, s, err = ecdsa.Sign(config.Random(), pk, digest) | |||
| } else { | |||
| var b []byte | |||
| b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, nil) | |||
| if err == nil { | |||
| r, s, err = unwrapECDSASig(b) | |||
| } | |||
| r, s, err := ecdsa.Sign(config.Random(), priv.PrivateKey.(*ecdsa.PrivateKey), digest) | |||
| if err == nil { | |||
| sig.ECDSASigR = FromBig(r) | |||
| sig.ECDSASigS = FromBig(s) | |||
| } | |||
| case PubKeyAlgoEdDSA: | |||
| r, s, err := priv.PrivateKey.(*EdDSAPrivateKey).Sign(digest) | |||
| if err == nil { | |||
| sig.ECDSASigR = fromBig(r) | |||
| sig.ECDSASigS = fromBig(s) | |||
| sig.EdDSASigR = FromBytes(r) | |||
| sig.EdDSASigS = FromBytes(s) | |||
| } | |||
| default: | |||
| err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) | |||
| @@ -558,19 +662,6 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e | |||
| return | |||
| } | |||
| // unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA | |||
| // signature. | |||
| func unwrapECDSASig(b []byte) (r, s *big.Int, err error) { | |||
| var ecsdaSig struct { | |||
| R, S *big.Int | |||
| } | |||
| _, err = asn1.Unmarshal(b, &ecsdaSig) | |||
| if err != nil { | |||
| return | |||
| } | |||
| return ecsdaSig.R, ecsdaSig.S, nil | |||
| } | |||
| // SignUserId computes a signature from priv, asserting that pub is a valid | |||
| // key for the identity id. On success, the signature is stored in sig. Call | |||
| // Serialize to write it out. | |||
| @@ -583,6 +674,16 @@ func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, co | |||
| return sig.Sign(h, priv, config) | |||
| } | |||
| // SignUserIdWithSigner computes a signature from priv, asserting that pub is a | |||
| // valid key for the identity id. On success, the signature is stored in sig. | |||
| // Call Serialize to write it out. | |||
| // If config is nil, sensible defaults will be used. | |||
| func (sig *Signature) SignUserIdWithSigner(id string, pub *PublicKey, s Signer, config *Config) error { | |||
| updateUserIdSignatureHash(id, pub, s) | |||
| return sig.Sign(s, nil, config) | |||
| } | |||
| // SignKey computes a signature from priv, asserting that pub is a subkey. On | |||
| // success, the signature is stored in sig. Call Serialize to write it out. | |||
| // If config is nil, sensible defaults will be used. | |||
| @@ -594,13 +695,25 @@ func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) | |||
| return sig.Sign(h, priv, config) | |||
| } | |||
| // SignKeyWithSigner computes a signature using s, asserting that | |||
| // signeePubKey is a subkey. On success, the signature is stored in sig. Call | |||
| // Serialize to write it out. If config is nil, sensible defaults will be used. | |||
| func (sig *Signature) SignKeyWithSigner(signeePubKey *PublicKey, signerPubKey *PublicKey, s Signer, config *Config) error { | |||
| updateKeySignatureHash(signerPubKey, signeePubKey, s) | |||
| return sig.Sign(s, nil, config) | |||
| } | |||
| // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been | |||
| // called first. | |||
| func (sig *Signature) Serialize(w io.Writer) (err error) { | |||
| if len(sig.outSubpackets) == 0 { | |||
| sig.outSubpackets = sig.rawSubpackets | |||
| } | |||
| if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil && sig.ECDSASigR.bytes == nil { | |||
| if sig.RSASignature.bytes == nil && | |||
| sig.DSASigR.bytes == nil && | |||
| sig.ECDSASigR.bytes == nil && | |||
| sig.EdDSASigR.bytes == nil { | |||
| return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") | |||
| } | |||
| @@ -611,6 +724,9 @@ func (sig *Signature) Serialize(w io.Writer) (err error) { | |||
| case PubKeyAlgoDSA: | |||
| sigLength = 2 + len(sig.DSASigR.bytes) | |||
| sigLength += 2 + len(sig.DSASigS.bytes) | |||
| case PubKeyAlgoEdDSA: | |||
| sigLength = 2 + len(sig.EdDSASigR.bytes) | |||
| sigLength += 2 + len(sig.EdDSASigS.bytes) | |||
| case PubKeyAlgoECDSA: | |||
| sigLength = 2 + len(sig.ECDSASigR.bytes) | |||
| sigLength += 2 + len(sig.ECDSASigS.bytes) | |||
| @@ -651,6 +767,8 @@ func (sig *Signature) Serialize(w io.Writer) (err error) { | |||
| err = writeMPIs(w, sig.RSASignature) | |||
| case PubKeyAlgoDSA: | |||
| err = writeMPIs(w, sig.DSASigR, sig.DSASigS) | |||
| case PubKeyAlgoEdDSA: | |||
| err = writeMPIs(w, sig.EdDSASigR, sig.EdDSASigS) | |||
| case PubKeyAlgoECDSA: | |||
| err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS) | |||
| default: | |||
| @@ -687,20 +805,7 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { | |||
| // Key flags may only appear in self-signatures or certification signatures. | |||
| if sig.FlagsValid { | |||
| var flags byte | |||
| if sig.FlagCertify { | |||
| flags |= KeyFlagCertify | |||
| } | |||
| if sig.FlagSign { | |||
| flags |= KeyFlagSign | |||
| } | |||
| if sig.FlagEncryptCommunications { | |||
| flags |= KeyFlagEncryptCommunications | |||
| } | |||
| if sig.FlagEncryptStorage { | |||
| flags |= KeyFlagEncryptStorage | |||
| } | |||
| subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}}) | |||
| subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{sig.GetKeyFlags().BitField}}) | |||
| } | |||
| // The following subpackets may only appear in self-signatures | |||
| @@ -729,3 +834,47 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { | |||
| return | |||
| } | |||
| func (sig *Signature) GetKeyFlags() (ret KeyFlagBits) { | |||
| if !sig.FlagsValid { | |||
| return ret | |||
| } | |||
| ret.Valid = true | |||
| if sig.FlagCertify { | |||
| ret.BitField |= KeyFlagCertify | |||
| } | |||
| if sig.FlagSign { | |||
| ret.BitField |= KeyFlagSign | |||
| } | |||
| if sig.FlagEncryptCommunications { | |||
| ret.BitField |= KeyFlagEncryptCommunications | |||
| } | |||
| if sig.FlagEncryptStorage { | |||
| ret.BitField |= KeyFlagEncryptStorage | |||
| } | |||
| return ret | |||
| } | |||
| func (f *KeyFlagBits) HasFlagCertify() bool { | |||
| return f.BitField&KeyFlagCertify != 0 | |||
| } | |||
| func (f *KeyFlagBits) HasFlagSign() bool { | |||
| return f.BitField&KeyFlagSign != 0 | |||
| } | |||
| func (f *KeyFlagBits) HasFlagEncryptCommunications() bool { | |||
| return f.BitField&KeyFlagEncryptCommunications != 0 | |||
| } | |||
| func (f *KeyFlagBits) HasFlagEncryptStorage() bool { | |||
| return f.BitField&KeyFlagEncryptStorage != 0 | |||
| } | |||
| func (f *KeyFlagBits) Merge(other KeyFlagBits) { | |||
| if other.Valid { | |||
| f.Valid = true | |||
| f.BitField |= other.BitField | |||
| } | |||
| } | |||
| @@ -12,8 +12,8 @@ import ( | |||
| "strconv" | |||
| "time" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "golang.org/x/crypto/openpgp/s2k" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/s2k" | |||
| ) | |||
| // SignatureV3 represents older version 3 signatures. These signatures are less secure | |||
| @@ -10,8 +10,8 @@ import ( | |||
| "io" | |||
| "strconv" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "golang.org/x/crypto/openpgp/s2k" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/s2k" | |||
| ) | |||
| // This is the largest session key that we'll support. Since no 512-bit cipher | |||
| @@ -48,6 +48,9 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error { | |||
| if err != nil { | |||
| return err | |||
| } | |||
| if ske.s2k == nil { | |||
| return errors.UnsupportedError("can't use dummy S2K for symmetric key encryption") | |||
| } | |||
| encryptedKey := make([]byte, maxSessionKeySizeInBytes) | |||
| // The session key may follow. We just have to try and read to find | |||
| @@ -8,10 +8,11 @@ import ( | |||
| "crypto/cipher" | |||
| "crypto/sha1" | |||
| "crypto/subtle" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "hash" | |||
| "io" | |||
| "strconv" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| ) | |||
| // SymmetricallyEncrypted represents a symmetrically encrypted byte string. The | |||
| @@ -0,0 +1,7 @@ | |||
| #!/bin/sh | |||
| patch < sig-v3.patch | |||
| patch < s2k-gnu-dummy.patch | |||
| find . -type f -name '*.go' -exec sed -i'' -e 's/golang.org\/x\/crypto\/openpgp/github.com\/keybase\/go-crypto\/openpgp/' {} \; | |||
| find . -type f -name '*.go-e' -exec rm {} \; | |||
| go test ./... | |||
| @@ -3,18 +3,19 @@ | |||
| // license that can be found in the LICENSE file. | |||
| // Package openpgp implements high level operations on OpenPGP messages. | |||
| package openpgp // import "golang.org/x/crypto/openpgp" | |||
| package openpgp // import "github.com/keybase/go-crypto/openpgp" | |||
| import ( | |||
| "crypto" | |||
| "crypto/hmac" | |||
| _ "crypto/sha256" | |||
| "hash" | |||
| "io" | |||
| "strconv" | |||
| "golang.org/x/crypto/openpgp/armor" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "golang.org/x/crypto/openpgp/packet" | |||
| "github.com/keybase/go-crypto/openpgp/armor" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/packet" | |||
| ) | |||
| // SignatureType is the armor type for a PGP signature. | |||
| @@ -50,7 +51,7 @@ type MessageDetails struct { | |||
| // If IsSigned is true and SignedBy is non-zero then the signature will | |||
| // be verified as UnverifiedBody is read. The signature cannot be | |||
| // checked until the whole of UnverifiedBody is read so UnverifiedBody | |||
| // must be consumed until EOF before the data can be trusted. Even if a | |||
| // must be consumed until EOF before the data can trusted. Even if a | |||
| // message isn't signed (or the signer is unknown) the data may contain | |||
| // an authentication code that is only checked once UnverifiedBody has | |||
| // been consumed. Once EOF has been seen, the following fields are | |||
| @@ -113,7 +114,7 @@ ParsePackets: | |||
| // This packet contains the decryption key encrypted to a public key. | |||
| md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) | |||
| switch p.Algo { | |||
| case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal: | |||
| case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH: | |||
| break | |||
| default: | |||
| continue | |||
| @@ -122,7 +123,7 @@ ParsePackets: | |||
| if p.KeyId == 0 { | |||
| keys = keyring.DecryptionKeys() | |||
| } else { | |||
| keys = keyring.KeysById(p.KeyId) | |||
| keys = keyring.KeysById(p.KeyId, nil) | |||
| } | |||
| for _, k := range keys { | |||
| pubKeys = append(pubKeys, keyEnvelopePair{k, p}) | |||
| @@ -255,7 +256,7 @@ FindLiteralData: | |||
| md.IsSigned = true | |||
| md.SignedByKeyId = p.KeyId | |||
| keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign) | |||
| keys := keyring.KeysByIdUsage(p.KeyId, nil, packet.KeyFlagSign) | |||
| if len(keys) > 0 { | |||
| md.SignedBy = &keys[0] | |||
| } | |||
| @@ -336,7 +337,16 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { | |||
| var ok bool | |||
| if scr.md.Signature, ok = p.(*packet.Signature); ok { | |||
| scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | |||
| var err error | |||
| if fingerprint := scr.md.Signature.IssuerFingerprint; fingerprint != nil { | |||
| if !hmac.Equal(fingerprint, scr.md.SignedBy.PublicKey.Fingerprint[:]) { | |||
| err = errors.StructuralError("bad key fingerprint") | |||
| } | |||
| } | |||
| if err == nil { | |||
| err = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | |||
| } | |||
| scr.md.SignatureError = err | |||
| } else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { | |||
| scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) | |||
| } else { | |||
| @@ -361,7 +371,13 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { | |||
| // returns the signer if the signature is valid. If the signer isn't known, | |||
| // ErrUnknownIssuer is returned. | |||
| func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { | |||
| signer, _, err = checkDetachedSignature(keyring, signed, signature) | |||
| return signer, err | |||
| } | |||
| func checkDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, issuer *uint64, err error) { | |||
| var issuerKeyId uint64 | |||
| var issuerFingerprint []byte | |||
| var hashFunc crypto.Hash | |||
| var sigType packet.SignatureType | |||
| var keys []Key | |||
| @@ -371,29 +387,30 @@ func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signe | |||
| for { | |||
| p, err = packets.Next() | |||
| if err == io.EOF { | |||
| return nil, errors.ErrUnknownIssuer | |||
| return nil, nil, errors.ErrUnknownIssuer | |||
| } | |||
| if err != nil { | |||
| return nil, err | |||
| return nil, nil, err | |||
| } | |||
| switch sig := p.(type) { | |||
| case *packet.Signature: | |||
| if sig.IssuerKeyId == nil { | |||
| return nil, errors.StructuralError("signature doesn't have an issuer") | |||
| return nil, nil, errors.StructuralError("signature doesn't have an issuer") | |||
| } | |||
| issuerKeyId = *sig.IssuerKeyId | |||
| hashFunc = sig.Hash | |||
| sigType = sig.SigType | |||
| issuerFingerprint = sig.IssuerFingerprint | |||
| case *packet.SignatureV3: | |||
| issuerKeyId = sig.IssuerKeyId | |||
| hashFunc = sig.Hash | |||
| sigType = sig.SigType | |||
| default: | |||
| return nil, errors.StructuralError("non signature packet found") | |||
| return nil, nil, errors.StructuralError("non signature packet found") | |||
| } | |||
| keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) | |||
| keys = keyring.KeysByIdUsage(issuerKeyId, issuerFingerprint, packet.KeyFlagSign) | |||
| if len(keys) > 0 { | |||
| break | |||
| } | |||
| @@ -405,11 +422,11 @@ func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signe | |||
| h, wrappedHash, err := hashForSignature(hashFunc, sigType) | |||
| if err != nil { | |||
| return nil, err | |||
| return nil, nil, err | |||
| } | |||
| if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF { | |||
| return nil, err | |||
| return nil, nil, err | |||
| } | |||
| for _, key := range keys { | |||
| @@ -423,20 +440,24 @@ func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signe | |||
| } | |||
| if err == nil { | |||
| return key.Entity, nil | |||
| return key.Entity, &issuerKeyId, nil | |||
| } | |||
| } | |||
| return nil, err | |||
| return nil, nil, err | |||
| } | |||
| // CheckArmoredDetachedSignature performs the same actions as | |||
| // CheckDetachedSignature but expects the signature to be armored. | |||
| func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { | |||
| signer, _, err = checkArmoredDetachedSignature(keyring, signed, signature) | |||
| return signer, err | |||
| } | |||
| func checkArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, issuer *uint64, err error) { | |||
| body, err := readArmored(signature, SignatureType) | |||
| if err != nil { | |||
| return | |||
| } | |||
| return CheckDetachedSignature(keyring, signed, body) | |||
| return checkDetachedSignature(keyring, signed, body) | |||
| } | |||
| @@ -4,7 +4,7 @@ | |||
| // Package s2k implements the various OpenPGP string-to-key transforms as | |||
| // specified in RFC 4800 section 3.7.1. | |||
| package s2k // import "golang.org/x/crypto/openpgp/s2k" | |||
| package s2k // import "github.com/keybase/go-crypto/openpgp/s2k" | |||
| import ( | |||
| "crypto" | |||
| @@ -12,7 +12,7 @@ import ( | |||
| "io" | |||
| "strconv" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| ) | |||
| // Config collects configuration parameters for s2k key-stretching | |||
| @@ -151,6 +151,53 @@ func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { | |||
| } | |||
| } | |||
| func parseGNUExtensions(r io.Reader) (f func(out, in []byte), err error) { | |||
| var buf [9]byte | |||
| // A three-byte string identifier | |||
| _, err = io.ReadFull(r, buf[:3]) | |||
| if err != nil { | |||
| return | |||
| } | |||
| gnuExt := string(buf[:3]) | |||
| if gnuExt != "GNU" { | |||
| return nil, errors.UnsupportedError("Malformed GNU extension: " + gnuExt) | |||
| } | |||
| _, err = io.ReadFull(r, buf[:1]) | |||
| if err != nil { | |||
| return | |||
| } | |||
| gnuExtType := int(buf[0]) | |||
| switch gnuExtType { | |||
| case 1: | |||
| return nil, nil | |||
| case 2: | |||
| // Read a serial number, which is prefixed by a 1-byte length. | |||
| // The maximum length is 16. | |||
| var lenBuf [1]byte | |||
| _, err = io.ReadFull(r, lenBuf[:]) | |||
| if err != nil { | |||
| return | |||
| } | |||
| maxLen := 16 | |||
| ivLen := int(lenBuf[0]) | |||
| if ivLen > maxLen { | |||
| ivLen = maxLen | |||
| } | |||
| ivBuf := make([]byte, ivLen) | |||
| // For now we simply discard the IV | |||
| _, err = io.ReadFull(r, ivBuf) | |||
| if err != nil { | |||
| return | |||
| } | |||
| return nil, nil | |||
| default: | |||
| return nil, errors.UnsupportedError("unknown S2K GNU protection mode: " + strconv.Itoa(int(gnuExtType))) | |||
| } | |||
| } | |||
| // Parse reads a binary specification for a string-to-key transformation from r | |||
| // and returns a function which performs that transform. | |||
| func Parse(r io.Reader) (f func(out, in []byte), err error) { | |||
| @@ -161,6 +208,12 @@ func Parse(r io.Reader) (f func(out, in []byte), err error) { | |||
| return | |||
| } | |||
| // GNU Extensions; handle them before we try to look for a hash, which won't | |||
| // be needed in most cases anyway. | |||
| if buf[0] == 101 { | |||
| return parseGNUExtensions(r) | |||
| } | |||
| hash, ok := HashIdToHash(buf[1]) | |||
| if !ok { | |||
| return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1]))) | |||
| @@ -251,7 +304,7 @@ func HashIdToHash(id byte) (h crypto.Hash, ok bool) { | |||
| } | |||
| // HashIdToString returns the name of the hash function corresponding to the | |||
| // given OpenPGP hash id. | |||
| // given OpenPGP hash id, or panics if id is unknown. | |||
| func HashIdToString(id byte) (name string, ok bool) { | |||
| for _, m := range hashToHashIdMapping { | |||
| if m.id == id { | |||
| @@ -0,0 +1,135 @@ | |||
| diff --git a/openpgp/read.go b/openpgp/read.go | |||
| index a6cecc5..0c9397b 100644 | |||
| --- a/openpgp/read.go | |||
| +++ b/openpgp/read.go | |||
| @@ -56,8 +56,9 @@ type MessageDetails struct { | |||
| // been consumed. Once EOF has been seen, the following fields are | |||
| // valid. (An authentication code failure is reported as a | |||
| // SignatureError error when reading from UnverifiedBody.) | |||
| - SignatureError error // nil if the signature is good. | |||
| - Signature *packet.Signature // the signature packet itself. | |||
| + SignatureError error // nil if the signature is good. | |||
| + Signature *packet.Signature // the signature packet itself, if v4 (default) | |||
| + SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature | |||
| decrypted io.ReadCloser | |||
| } | |||
| @@ -334,13 +335,15 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { | |||
| } | |||
| var ok bool | |||
| - if scr.md.Signature, ok = p.(*packet.Signature); !ok { | |||
| + if scr.md.Signature, ok = p.(*packet.Signature); ok { | |||
| + scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | |||
| + } else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { | |||
| + scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) | |||
| + } else { | |||
| scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") | |||
| return | |||
| } | |||
| - scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | |||
| - | |||
| // The SymmetricallyEncrypted packet, if any, might have an | |||
| // unsigned hash of its own. In order to check this we need to | |||
| // close that Reader. | |||
| diff --git a/openpgp/read_test.go b/openpgp/read_test.go | |||
| index 52f942c..abe8d7b 100644 | |||
| --- a/openpgp/read_test.go | |||
| +++ b/openpgp/read_test.go | |||
| @@ -13,6 +13,7 @@ import ( | |||
| "strings" | |||
| "testing" | |||
| + "golang.org/x/crypto/openpgp/armor" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| ) | |||
| @@ -411,6 +412,50 @@ func TestIssue11504(t *testing.T) { | |||
| testReadMessageError(t, "9303000130303030303030303030983002303030303030030000000130") | |||
| } | |||
| +// TestSignatureV3Message tests the verification of V3 signature, generated | |||
| +// with a modern V4-style key. Some people have their clients set to generate | |||
| +// V3 signatures, so it's useful to be able to verify them. | |||
| +func TestSignatureV3Message(t *testing.T) { | |||
| + sig, err := armor.Decode(strings.NewReader(signedMessageV3)) | |||
| + if err != nil { | |||
| + t.Error(err) | |||
| + return | |||
| + } | |||
| + key, err := ReadArmoredKeyRing(strings.NewReader(keyV4forVerifyingSignedMessageV3)) | |||
| + if err != nil { | |||
| + t.Error(err) | |||
| + return | |||
| + } | |||
| + md, err := ReadMessage(sig.Body, key, nil, nil) | |||
| + if err != nil { | |||
| + t.Error(err) | |||
| + return | |||
| + } | |||
| + | |||
| + _, err = ioutil.ReadAll(md.UnverifiedBody) | |||
| + if err != nil { | |||
| + t.Error(err) | |||
| + return | |||
| + } | |||
| + | |||
| + // We'll see a sig error here after reading in the UnverifiedBody above, | |||
| + // if there was one to see. | |||
| + if err = md.SignatureError; err != nil { | |||
| + t.Error(err) | |||
| + return | |||
| + } | |||
| + | |||
| + if md.SignatureV3 == nil { | |||
| + t.Errorf("No available signature after checking signature") | |||
| + return | |||
| + } | |||
| + if md.Signature != nil { | |||
| + t.Errorf("Did not expect a signature V4 back") | |||
| + return | |||
| + } | |||
| + return | |||
| +} | |||
| + | |||
| const testKey1KeyId = 0xA34D7E18C20C31BB | |||
| const testKey3KeyId = 0x338934250CCC0360 | |||
| @@ -504,3 +549,36 @@ const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6 | |||
| const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101` | |||
| const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000` | |||
| + | |||
| +const keyV4forVerifyingSignedMessageV3 = `-----BEGIN PGP PUBLIC KEY BLOCK----- | |||
| +Comment: GPGTools - https://gpgtools.org | |||
| + | |||
| +mI0EVfxoFQEEAMBIqmbDfYygcvP6Phr1wr1XI41IF7Qixqybs/foBF8qqblD9gIY | |||
| +BKpXjnBOtbkcVOJ0nljd3/sQIfH4E0vQwK5/4YRQSI59eKOqd6Fx+fWQOLG+uu6z | |||
| +tewpeCj9LLHvibx/Sc7VWRnrznia6ftrXxJ/wHMezSab3tnGC0YPVdGNABEBAAG0 | |||
| +JEdvY3J5cHRvIFRlc3QgS2V5IDx0aGVtYXhAZ21haWwuY29tPoi5BBMBCgAjBQJV | |||
| +/GgVAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQeXnQmhdGW9PFVAP+ | |||
| +K7TU0qX5ArvIONIxh/WAweyOk884c5cE8f+3NOPOOCRGyVy0FId5A7MmD5GOQh4H | |||
| +JseOZVEVCqlmngEvtHZb3U1VYtVGE5WZ+6rQhGsMcWP5qaT4soYwMBlSYxgYwQcx | |||
| +YhN9qOr292f9j2Y//TTIJmZT4Oa+lMxhWdqTfX+qMgG4jQRV/GgVAQQArhFSiij1 | |||
| +b+hT3dnapbEU+23Z1yTu1DfF6zsxQ4XQWEV3eR8v+8mEDDNcz8oyyF56k6UQ3rXi | |||
| +UMTIwRDg4V6SbZmaFbZYCOwp/EmXJ3rfhm7z7yzXj2OFN22luuqbyVhuL7LRdB0M | |||
| +pxgmjXb4tTvfgKd26x34S+QqUJ7W6uprY4sAEQEAAYifBBgBCgAJBQJV/GgVAhsM | |||
| +AAoJEHl50JoXRlvT7y8D/02ckx4OMkKBZo7viyrBw0MLG92i+DC2bs35PooHR6zz | |||
| +786mitjOp5z2QWNLBvxC70S0qVfCIz8jKupO1J6rq6Z8CcbLF3qjm6h1omUBf8Nd | |||
| +EfXKD2/2HV6zMKVknnKzIEzauh+eCKS2CeJUSSSryap/QLVAjRnckaES/OsEWhNB | |||
| +=RZia | |||
| +-----END PGP PUBLIC KEY BLOCK----- | |||
| +` | |||
| + | |||
| +const signedMessageV3 = `-----BEGIN PGP MESSAGE----- | |||
| +Comment: GPGTools - https://gpgtools.org | |||
| + | |||
| +owGbwMvMwMVYWXlhlrhb9GXG03JJDKF/MtxDMjKLFYAoUaEktbhEITe1uDgxPVWP | |||
| +q5NhKjMrWAVcC9evD8z/bF/uWNjqtk/X3y5/38XGRQHm/57rrDRYuGnTw597Xqka | |||
| +uM3137/hH3Os+Jf2dc0fXOITKwJvXJvecPVs0ta+Vg7ZO1MLn8w58Xx+6L58mbka | |||
| +DGHyU9yTueZE8D+QF/Tz28Y78dqtF56R1VPn9Xw4uJqrWYdd7b3vIZ1V6R4Nh05d | |||
| +iT57d/OhWwA= | |||
| +=hG7R | |||
| +-----END PGP MESSAGE----- | |||
| +` | |||
| @@ -11,10 +11,10 @@ import ( | |||
| "strconv" | |||
| "time" | |||
| "golang.org/x/crypto/openpgp/armor" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "golang.org/x/crypto/openpgp/packet" | |||
| "golang.org/x/crypto/openpgp/s2k" | |||
| "github.com/keybase/go-crypto/openpgp/armor" | |||
| "github.com/keybase/go-crypto/openpgp/errors" | |||
| "github.com/keybase/go-crypto/openpgp/packet" | |||
| "github.com/keybase/go-crypto/openpgp/s2k" | |||
| ) | |||
| // DetachSign signs message with the private key from signer (which must | |||
| @@ -59,20 +59,57 @@ func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType p | |||
| return out.Close() | |||
| } | |||
| // SignWithSigner signs the message of type sigType with s and writes the | |||
| // signature to w. | |||
| // If config is nil, sensible defaults will be used. | |||
| func SignWithSigner(s packet.Signer, w io.Writer, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | |||
| keyId := s.KeyId() | |||
| sig := new(packet.Signature) | |||
| sig.SigType = sigType | |||
| sig.PubKeyAlgo = s.PublicKeyAlgo() | |||
| sig.Hash = config.Hash() | |||
| sig.CreationTime = config.Now() | |||
| sig.IssuerKeyId = &keyId | |||
| s.Reset() | |||
| wrapped := s.(hash.Hash) | |||
| if sigType == packet.SigTypeText { | |||
| wrapped = NewCanonicalTextHash(s) | |||
| } | |||
| io.Copy(wrapped, message) | |||
| err = sig.Sign(s, nil, config) | |||
| if err != nil { | |||
| return | |||
| } | |||
| err = sig.Serialize(w) | |||
| return | |||
| } | |||
| func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | |||
| if signer.PrivateKey == nil { | |||
| signerSubkey, ok := signer.signingKey(config.Now()) | |||
| if !ok { | |||
| err = errors.InvalidArgumentError("no valid signing keys") | |||
| return | |||
| } | |||
| if signerSubkey.PrivateKey == nil { | |||
| return errors.InvalidArgumentError("signing key doesn't have a private key") | |||
| } | |||
| if signer.PrivateKey.Encrypted { | |||
| if signerSubkey.PrivateKey.Encrypted { | |||
| return errors.InvalidArgumentError("signing key is encrypted") | |||
| } | |||
| sig := new(packet.Signature) | |||
| sig.SigType = sigType | |||
| sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo | |||
| sig.PubKeyAlgo = signerSubkey.PrivateKey.PubKeyAlgo | |||
| sig.Hash = config.Hash() | |||
| sig.CreationTime = config.Now() | |||
| sig.IssuerKeyId = &signer.PrivateKey.KeyId | |||
| sig.IssuerKeyId = &signerSubkey.PrivateKey.KeyId | |||
| h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) | |||
| if err != nil { | |||
| @@ -80,7 +117,7 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S | |||
| } | |||
| io.Copy(wrappedHash, message) | |||
| err = sig.Sign(h, signer.PrivateKey, config) | |||
| err = sig.Sign(h, signerSubkey.PrivateKey, config) | |||
| if err != nil { | |||
| return | |||
| } | |||
| @@ -198,11 +235,20 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint | |||
| hashToHashId(crypto.SHA1), | |||
| hashToHashId(crypto.RIPEMD160), | |||
| } | |||
| // In the event that a recipient doesn't specify any supported ciphers | |||
| // or hash functions, these are the ones that we assume that every | |||
| // implementation supports. | |||
| defaultCiphers := candidateCiphers[len(candidateCiphers)-1:] | |||
| defaultHashes := candidateHashes[len(candidateHashes)-1:] | |||
| // If no preferences were specified, assume something safe and reasonable. | |||
| defaultCiphers := []uint8{ | |||
| uint8(packet.CipherAES128), | |||
| uint8(packet.CipherAES192), | |||
| uint8(packet.CipherAES256), | |||
| uint8(packet.CipherCAST5), | |||
| } | |||
| defaultHashes := []uint8{ | |||
| hashToHashId(crypto.SHA256), | |||
| hashToHashId(crypto.SHA512), | |||
| hashToHashId(crypto.RIPEMD160), | |||
| } | |||
| encryptKeys := make([]Key, len(to)) | |||
| for i := range to { | |||
| @@ -226,12 +272,15 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint | |||
| candidateHashes = intersectPreferences(candidateHashes, preferredHashes) | |||
| } | |||
| if len(candidateCiphers) == 0 || len(candidateHashes) == 0 { | |||
| return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms") | |||
| if len(candidateCiphers) == 0 { | |||
| return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common ciphers") | |||
| } | |||
| if len(candidateHashes) == 0 { | |||
| return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common hashes") | |||
| } | |||
| cipher := packet.CipherFunction(candidateCiphers[0]) | |||
| // If the cipher specified by config is a candidate, we'll use that. | |||
| // If the cipher specifed by config is a candidate, we'll use that. | |||
| configuredCipher := config.Cipher() | |||
| for _, c := range candidateCiphers { | |||
| cipherFunc := packet.CipherFunction(c) | |||
| @@ -376,3 +425,71 @@ func (c noOpCloser) Write(data []byte) (n int, err error) { | |||
| func (c noOpCloser) Close() error { | |||
| return nil | |||
| } | |||
| // AttachedSign is like openpgp.Encrypt (as in p.crypto/openpgp/write.go), but | |||
| // don't encrypt at all, just sign the literal unencrypted data. | |||
| // Unfortunately we need to duplicate some code here that's already | |||
| // in write.go | |||
| func AttachedSign(out io.WriteCloser, signed Entity, hints *FileHints, | |||
| config *packet.Config) (in io.WriteCloser, err error) { | |||
| if hints == nil { | |||
| hints = &FileHints{} | |||
| } | |||
| if config == nil { | |||
| config = &packet.Config{} | |||
| } | |||
| var signer *packet.PrivateKey | |||
| signKey, ok := signed.signingKey(config.Now()) | |||
| if !ok { | |||
| err = errors.InvalidArgumentError("no valid signing keys") | |||
| return | |||
| } | |||
| signer = signKey.PrivateKey | |||
| if signer == nil { | |||
| err = errors.InvalidArgumentError("no valid signing keys") | |||
| return | |||
| } | |||
| if signer.Encrypted { | |||
| err = errors.InvalidArgumentError("signing key must be decrypted") | |||
| return | |||
| } | |||
| hasher := crypto.SHA512 | |||
| ops := &packet.OnePassSignature{ | |||
| SigType: packet.SigTypeBinary, | |||
| Hash: hasher, | |||
| PubKeyAlgo: signer.PubKeyAlgo, | |||
| KeyId: signer.KeyId, | |||
| IsLast: true, | |||
| } | |||
| if err = ops.Serialize(out); err != nil { | |||
| return | |||
| } | |||
| var epochSeconds uint32 | |||
| if !hints.ModTime.IsZero() { | |||
| epochSeconds = uint32(hints.ModTime.Unix()) | |||
| } | |||
| // We don't want the literal serializer to closer the output stream | |||
| // since we're going to need to write to it when we finish up the | |||
| // signature stuff. | |||
| in, err = packet.SerializeLiteral(noOpCloser{out}, hints.IsBinary, hints.FileName, epochSeconds) | |||
| if err != nil { | |||
| return | |||
| } | |||
| // If we need to write a signature packet after the literal | |||
| // data then we need to stop literalData from closing | |||
| // encryptedData. | |||
| in = signatureWriter{out, in, hasher, hasher.New(), signer, config} | |||
| return | |||
| } | |||
| @@ -0,0 +1,325 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package rsa | |||
| import ( | |||
| "crypto" | |||
| "crypto/subtle" | |||
| "errors" | |||
| "io" | |||
| "math/big" | |||
| ) | |||
| // This file implements encryption and decryption using PKCS#1 v1.5 padding. | |||
| // PKCS1v15DecrypterOpts is for passing options to PKCS#1 v1.5 decryption using | |||
| // the crypto.Decrypter interface. | |||
| type PKCS1v15DecryptOptions struct { | |||
| // SessionKeyLen is the length of the session key that is being | |||
| // decrypted. If not zero, then a padding error during decryption will | |||
| // cause a random plaintext of this length to be returned rather than | |||
| // an error. These alternatives happen in constant time. | |||
| SessionKeyLen int | |||
| } | |||
| // EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5. | |||
| // The message must be no longer than the length of the public modulus minus 11 bytes. | |||
| // | |||
| // The rand parameter is used as a source of entropy to ensure that encrypting | |||
| // the same message twice doesn't result in the same ciphertext. | |||
| // | |||
| // WARNING: use of this function to encrypt plaintexts other than session keys | |||
| // is dangerous. Use RSA OAEP in new protocols. | |||
| func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) { | |||
| if err := checkPub(pub); err != nil { | |||
| return nil, err | |||
| } | |||
| k := (pub.N.BitLen() + 7) / 8 | |||
| if len(msg) > k-11 { | |||
| err = ErrMessageTooLong | |||
| return | |||
| } | |||
| // EM = 0x00 || 0x02 || PS || 0x00 || M | |||
| em := make([]byte, k) | |||
| em[1] = 2 | |||
| ps, mm := em[2:len(em)-len(msg)-1], em[len(em)-len(msg):] | |||
| err = nonZeroRandomBytes(ps, rand) | |||
| if err != nil { | |||
| return | |||
| } | |||
| em[len(em)-len(msg)-1] = 0 | |||
| copy(mm, msg) | |||
| m := new(big.Int).SetBytes(em) | |||
| c := encrypt(new(big.Int), pub, m) | |||
| copyWithLeftPad(em, c.Bytes()) | |||
| out = em | |||
| return | |||
| } | |||
| // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5. | |||
| // If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. | |||
| // | |||
| // Note that whether this function returns an error or not discloses secret | |||
| // information. If an attacker can cause this function to run repeatedly and | |||
| // learn whether each instance returned an error then they can decrypt and | |||
| // forge signatures as if they had the private key. See | |||
| // DecryptPKCS1v15SessionKey for a way of solving this problem. | |||
| func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) { | |||
| if err := checkPub(&priv.PublicKey); err != nil { | |||
| return nil, err | |||
| } | |||
| valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext) | |||
| if err != nil { | |||
| return | |||
| } | |||
| if valid == 0 { | |||
| return nil, ErrDecryption | |||
| } | |||
| out = out[index:] | |||
| return | |||
| } | |||
| // DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5. | |||
| // If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. | |||
| // It returns an error if the ciphertext is the wrong length or if the | |||
| // ciphertext is greater than the public modulus. Otherwise, no error is | |||
| // returned. If the padding is valid, the resulting plaintext message is copied | |||
| // into key. Otherwise, key is unchanged. These alternatives occur in constant | |||
| // time. It is intended that the user of this function generate a random | |||
| // session key beforehand and continue the protocol with the resulting value. | |||
| // This will remove any possibility that an attacker can learn any information | |||
| // about the plaintext. | |||
| // See ``Chosen Ciphertext Attacks Against Protocols Based on the RSA | |||
| // Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology | |||
| // (Crypto '98). | |||
| // | |||
| // Note that if the session key is too small then it may be possible for an | |||
| // attacker to brute-force it. If they can do that then they can learn whether | |||
| // a random value was used (because it'll be different for the same ciphertext) | |||
| // and thus whether the padding was correct. This defeats the point of this | |||
| // function. Using at least a 16-byte key will protect against this attack. | |||
| func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) { | |||
| if err := checkPub(&priv.PublicKey); err != nil { | |||
| return err | |||
| } | |||
| k := (priv.N.BitLen() + 7) / 8 | |||
| if k-(len(key)+3+8) < 0 { | |||
| return ErrDecryption | |||
| } | |||
| valid, em, index, err := decryptPKCS1v15(rand, priv, ciphertext) | |||
| if err != nil { | |||
| return | |||
| } | |||
| if len(em) != k { | |||
| // This should be impossible because decryptPKCS1v15 always | |||
| // returns the full slice. | |||
| return ErrDecryption | |||
| } | |||
| valid &= subtle.ConstantTimeEq(int32(len(em)-index), int32(len(key))) | |||
| subtle.ConstantTimeCopy(valid, key, em[len(em)-len(key):]) | |||
| return | |||
| } | |||
| // decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation if | |||
| // rand is not nil. It returns one or zero in valid that indicates whether the | |||
| // plaintext was correctly structured. In either case, the plaintext is | |||
| // returned in em so that it may be read independently of whether it was valid | |||
| // in order to maintain constant memory access patterns. If the plaintext was | |||
| // valid then index contains the index of the original message in em. | |||
| func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) { | |||
| k := (priv.N.BitLen() + 7) / 8 | |||
| if k < 11 { | |||
| err = ErrDecryption | |||
| return | |||
| } | |||
| c := new(big.Int).SetBytes(ciphertext) | |||
| m, err := decrypt(rand, priv, c) | |||
| if err != nil { | |||
| return | |||
| } | |||
| em = leftPad(m.Bytes(), k) | |||
| firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) | |||
| secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2) | |||
| // The remainder of the plaintext must be a string of non-zero random | |||
| // octets, followed by a 0, followed by the message. | |||
| // lookingForIndex: 1 iff we are still looking for the zero. | |||
| // index: the offset of the first zero byte. | |||
| lookingForIndex := 1 | |||
| for i := 2; i < len(em); i++ { | |||
| equals0 := subtle.ConstantTimeByteEq(em[i], 0) | |||
| index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) | |||
| lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) | |||
| } | |||
| // The PS padding must be at least 8 bytes long, and it starts two | |||
| // bytes into em. | |||
| validPS := subtle.ConstantTimeLessOrEq(2+8, index) | |||
| valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1) & validPS | |||
| index = subtle.ConstantTimeSelect(valid, index+1, 0) | |||
| return valid, em, index, nil | |||
| } | |||
| // nonZeroRandomBytes fills the given slice with non-zero random octets. | |||
| func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { | |||
| _, err = io.ReadFull(rand, s) | |||
| if err != nil { | |||
| return | |||
| } | |||
| for i := 0; i < len(s); i++ { | |||
| for s[i] == 0 { | |||
| _, err = io.ReadFull(rand, s[i:i+1]) | |||
| if err != nil { | |||
| return | |||
| } | |||
| // In tests, the PRNG may return all zeros so we do | |||
| // this to break the loop. | |||
| s[i] ^= 0x42 | |||
| } | |||
| } | |||
| return | |||
| } | |||
| // These are ASN1 DER structures: | |||
| // DigestInfo ::= SEQUENCE { | |||
| // digestAlgorithm AlgorithmIdentifier, | |||
| // digest OCTET STRING | |||
| // } | |||
| // For performance, we don't use the generic ASN1 encoder. Rather, we | |||
| // precompute a prefix of the digest value that makes a valid ASN1 DER string | |||
| // with the correct contents. | |||
| var hashPrefixes = map[crypto.Hash][]byte{ | |||
| crypto.MD5: {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, | |||
| crypto.SHA1: {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}, | |||
| crypto.SHA224: {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, | |||
| crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, | |||
| crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, | |||
| crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, | |||
| crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix. | |||
| crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14}, | |||
| } | |||
| // SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5. | |||
| // Note that hashed must be the result of hashing the input message using the | |||
| // given hash function. If hash is zero, hashed is signed directly. This isn't | |||
| // advisable except for interoperability. | |||
| // | |||
| // If rand is not nil then RSA blinding will be used to avoid timing side-channel attacks. | |||
| // | |||
| // This function is deterministic. Thus, if the set of possible messages is | |||
| // small, an attacker may be able to build a map from messages to signatures | |||
| // and identify the signed messages. As ever, signatures provide authenticity, | |||
| // not confidentiality. | |||
| func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) { | |||
| hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) | |||
| if err != nil { | |||
| return | |||
| } | |||
| tLen := len(prefix) + hashLen | |||
| k := (priv.N.BitLen() + 7) / 8 | |||
| if k < tLen+11 { | |||
| return nil, ErrMessageTooLong | |||
| } | |||
| // EM = 0x00 || 0x01 || PS || 0x00 || T | |||
| em := make([]byte, k) | |||
| em[1] = 1 | |||
| for i := 2; i < k-tLen-1; i++ { | |||
| em[i] = 0xff | |||
| } | |||
| copy(em[k-tLen:k-hashLen], prefix) | |||
| copy(em[k-hashLen:k], hashed) | |||
| m := new(big.Int).SetBytes(em) | |||
| c, err := decryptAndCheck(rand, priv, m) | |||
| if err != nil { | |||
| return | |||
| } | |||
| copyWithLeftPad(em, c.Bytes()) | |||
| s = em | |||
| return | |||
| } | |||
| // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature. | |||
| // hashed is the result of hashing the input message using the given hash | |||
| // function and sig is the signature. A valid signature is indicated by | |||
| // returning a nil error. If hash is zero then hashed is used directly. This | |||
| // isn't advisable except for interoperability. | |||
| func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) { | |||
| hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) | |||
| if err != nil { | |||
| return | |||
| } | |||
| tLen := len(prefix) + hashLen | |||
| k := (pub.N.BitLen() + 7) / 8 | |||
| if k < tLen+11 { | |||
| err = ErrVerification | |||
| return | |||
| } | |||
| c := new(big.Int).SetBytes(sig) | |||
| m := encrypt(new(big.Int), pub, c) | |||
| em := leftPad(m.Bytes(), k) | |||
| // EM = 0x00 || 0x01 || PS || 0x00 || T | |||
| ok := subtle.ConstantTimeByteEq(em[0], 0) | |||
| ok &= subtle.ConstantTimeByteEq(em[1], 1) | |||
| ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed) | |||
| ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix) | |||
| ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0) | |||
| for i := 2; i < k-tLen-1; i++ { | |||
| ok &= subtle.ConstantTimeByteEq(em[i], 0xff) | |||
| } | |||
| if ok != 1 { | |||
| return ErrVerification | |||
| } | |||
| return nil | |||
| } | |||
| func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) { | |||
| // Special case: crypto.Hash(0) is used to indicate that the data is | |||
| // signed directly. | |||
| if hash == 0 { | |||
| return inLen, nil, nil | |||
| } | |||
| hashLen = hash.Size() | |||
| if inLen != hashLen { | |||
| return 0, nil, errors.New("crypto/rsa: input must be hashed message") | |||
| } | |||
| prefix, ok := hashPrefixes[hash] | |||
| if !ok { | |||
| return 0, nil, errors.New("crypto/rsa: unsupported hash function") | |||
| } | |||
| return | |||
| } | |||
| // copyWithLeftPad copies src to the end of dest, padding with zero bytes as | |||
| // needed. | |||
| func copyWithLeftPad(dest, src []byte) { | |||
| numPaddingBytes := len(dest) - len(src) | |||
| for i := 0; i < numPaddingBytes; i++ { | |||
| dest[i] = 0 | |||
| } | |||
| copy(dest[numPaddingBytes:], src) | |||
| } | |||
| @@ -0,0 +1,297 @@ | |||
| // Copyright 2013 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package rsa | |||
| // This file implements the PSS signature scheme [1]. | |||
| // | |||
| // [1] http://www.rsa.com/rsalabs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf | |||
| import ( | |||
| "bytes" | |||
| "crypto" | |||
| "errors" | |||
| "hash" | |||
| "io" | |||
| "math/big" | |||
| ) | |||
| func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) { | |||
| // See [1], section 9.1.1 | |||
| hLen := hash.Size() | |||
| sLen := len(salt) | |||
| emLen := (emBits + 7) / 8 | |||
| // 1. If the length of M is greater than the input limitation for the | |||
| // hash function (2^61 - 1 octets for SHA-1), output "message too | |||
| // long" and stop. | |||
| // | |||
| // 2. Let mHash = Hash(M), an octet string of length hLen. | |||
| if len(mHash) != hLen { | |||
| return nil, errors.New("crypto/rsa: input must be hashed message") | |||
| } | |||
| // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. | |||
| if emLen < hLen+sLen+2 { | |||
| return nil, errors.New("crypto/rsa: encoding error") | |||
| } | |||
| em := make([]byte, emLen) | |||
| db := em[:emLen-sLen-hLen-2+1+sLen] | |||
| h := em[emLen-sLen-hLen-2+1+sLen : emLen-1] | |||
| // 4. Generate a random octet string salt of length sLen; if sLen = 0, | |||
| // then salt is the empty string. | |||
| // | |||
| // 5. Let | |||
| // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; | |||
| // | |||
| // M' is an octet string of length 8 + hLen + sLen with eight | |||
| // initial zero octets. | |||
| // | |||
| // 6. Let H = Hash(M'), an octet string of length hLen. | |||
| var prefix [8]byte | |||
| hash.Write(prefix[:]) | |||
| hash.Write(mHash) | |||
| hash.Write(salt) | |||
| h = hash.Sum(h[:0]) | |||
| hash.Reset() | |||
| // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 | |||
| // zero octets. The length of PS may be 0. | |||
| // | |||
| // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length | |||
| // emLen - hLen - 1. | |||
| db[emLen-sLen-hLen-2] = 0x01 | |||
| copy(db[emLen-sLen-hLen-1:], salt) | |||
| // 9. Let dbMask = MGF(H, emLen - hLen - 1). | |||
| // | |||
| // 10. Let maskedDB = DB \xor dbMask. | |||
| mgf1XOR(db, hash, h) | |||
| // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in | |||
| // maskedDB to zero. | |||
| db[0] &= (0xFF >> uint(8*emLen-emBits)) | |||
| // 12. Let EM = maskedDB || H || 0xbc. | |||
| em[emLen-1] = 0xBC | |||
| // 13. Output EM. | |||
| return em, nil | |||
| } | |||
| func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { | |||
| // 1. If the length of M is greater than the input limitation for the | |||
| // hash function (2^61 - 1 octets for SHA-1), output "inconsistent" | |||
| // and stop. | |||
| // | |||
| // 2. Let mHash = Hash(M), an octet string of length hLen. | |||
| hLen := hash.Size() | |||
| if hLen != len(mHash) { | |||
| return ErrVerification | |||
| } | |||
| // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. | |||
| emLen := (emBits + 7) / 8 | |||
| if emLen < hLen+sLen+2 { | |||
| return ErrVerification | |||
| } | |||
| // 4. If the rightmost octet of EM does not have hexadecimal value | |||
| // 0xbc, output "inconsistent" and stop. | |||
| if em[len(em)-1] != 0xBC { | |||
| return ErrVerification | |||
| } | |||
| // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and | |||
| // let H be the next hLen octets. | |||
| db := em[:emLen-hLen-1] | |||
| h := em[emLen-hLen-1 : len(em)-1] | |||
| // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in | |||
| // maskedDB are not all equal to zero, output "inconsistent" and | |||
| // stop. | |||
| if em[0]&(0xFF<<uint(8-(8*emLen-emBits))) != 0 { | |||
| return ErrVerification | |||
| } | |||
| // 7. Let dbMask = MGF(H, emLen - hLen - 1). | |||
| // | |||
| // 8. Let DB = maskedDB \xor dbMask. | |||
| mgf1XOR(db, hash, h) | |||
| // 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB | |||
| // to zero. | |||
| db[0] &= (0xFF >> uint(8*emLen-emBits)) | |||
| if sLen == PSSSaltLengthAuto { | |||
| FindSaltLength: | |||
| for sLen = emLen - (hLen + 2); sLen >= 0; sLen-- { | |||
| switch db[emLen-hLen-sLen-2] { | |||
| case 1: | |||
| break FindSaltLength | |||
| case 0: | |||
| continue | |||
| default: | |||
| return ErrVerification | |||
| } | |||
| } | |||
| if sLen < 0 { | |||
| return ErrVerification | |||
| } | |||
| } else { | |||
| // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero | |||
| // or if the octet at position emLen - hLen - sLen - 1 (the leftmost | |||
| // position is "position 1") does not have hexadecimal value 0x01, | |||
| // output "inconsistent" and stop. | |||
| for _, e := range db[:emLen-hLen-sLen-2] { | |||
| if e != 0x00 { | |||
| return ErrVerification | |||
| } | |||
| } | |||
| if db[emLen-hLen-sLen-2] != 0x01 { | |||
| return ErrVerification | |||
| } | |||
| } | |||
| // 11. Let salt be the last sLen octets of DB. | |||
| salt := db[len(db)-sLen:] | |||
| // 12. Let | |||
| // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; | |||
| // M' is an octet string of length 8 + hLen + sLen with eight | |||
| // initial zero octets. | |||
| // | |||
| // 13. Let H' = Hash(M'), an octet string of length hLen. | |||
| var prefix [8]byte | |||
| hash.Write(prefix[:]) | |||
| hash.Write(mHash) | |||
| hash.Write(salt) | |||
| h0 := hash.Sum(nil) | |||
| // 14. If H = H', output "consistent." Otherwise, output "inconsistent." | |||
| if !bytes.Equal(h0, h) { | |||
| return ErrVerification | |||
| } | |||
| return nil | |||
| } | |||
| // signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt. | |||
| // Note that hashed must be the result of hashing the input message using the | |||
| // given hash function. salt is a random sequence of bytes whose length will be | |||
| // later used to verify the signature. | |||
| func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) { | |||
| nBits := priv.N.BitLen() | |||
| em, err := emsaPSSEncode(hashed, nBits-1, salt, hash.New()) | |||
| if err != nil { | |||
| return | |||
| } | |||
| m := new(big.Int).SetBytes(em) | |||
| c, err := decryptAndCheck(rand, priv, m) | |||
| if err != nil { | |||
| return | |||
| } | |||
| s = make([]byte, (nBits+7)/8) | |||
| copyWithLeftPad(s, c.Bytes()) | |||
| return | |||
| } | |||
| const ( | |||
| // PSSSaltLengthAuto causes the salt in a PSS signature to be as large | |||
| // as possible when signing, and to be auto-detected when verifying. | |||
| PSSSaltLengthAuto = 0 | |||
| // PSSSaltLengthEqualsHash causes the salt length to equal the length | |||
| // of the hash used in the signature. | |||
| PSSSaltLengthEqualsHash = -1 | |||
| ) | |||
| // PSSOptions contains options for creating and verifying PSS signatures. | |||
| type PSSOptions struct { | |||
| // SaltLength controls the length of the salt used in the PSS | |||
| // signature. It can either be a number of bytes, or one of the special | |||
| // PSSSaltLength constants. | |||
| SaltLength int | |||
| // Hash, if not zero, overrides the hash function passed to SignPSS. | |||
| // This is the only way to specify the hash function when using the | |||
| // crypto.Signer interface. | |||
| Hash crypto.Hash | |||
| } | |||
| // HashFunc returns pssOpts.Hash so that PSSOptions implements | |||
| // crypto.SignerOpts. | |||
| func (pssOpts *PSSOptions) HashFunc() crypto.Hash { | |||
| return pssOpts.Hash | |||
| } | |||
| func (opts *PSSOptions) saltLength() int { | |||
| if opts == nil { | |||
| return PSSSaltLengthAuto | |||
| } | |||
| return opts.SaltLength | |||
| } | |||
| // SignPSS calculates the signature of hashed using RSASSA-PSS [1]. | |||
| // Note that hashed must be the result of hashing the input message using the | |||
| // given hash function. The opts argument may be nil, in which case sensible | |||
| // defaults are used. | |||
| func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) { | |||
| saltLength := opts.saltLength() | |||
| switch saltLength { | |||
| case PSSSaltLengthAuto: | |||
| saltLength = (priv.N.BitLen()+7)/8 - 2 - hash.Size() | |||
| case PSSSaltLengthEqualsHash: | |||
| saltLength = hash.Size() | |||
| } | |||
| if opts != nil && opts.Hash != 0 { | |||
| hash = opts.Hash | |||
| } | |||
| salt := make([]byte, saltLength) | |||
| if _, err = io.ReadFull(rand, salt); err != nil { | |||
| return | |||
| } | |||
| return signPSSWithSalt(rand, priv, hash, hashed, salt) | |||
| } | |||
| // VerifyPSS verifies a PSS signature. | |||
| // hashed is the result of hashing the input message using the given hash | |||
| // function and sig is the signature. A valid signature is indicated by | |||
| // returning a nil error. The opts argument may be nil, in which case sensible | |||
| // defaults are used. | |||
| func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts *PSSOptions) error { | |||
| return verifyPSS(pub, hash, hashed, sig, opts.saltLength()) | |||
| } | |||
| // verifyPSS verifies a PSS signature with the given salt length. | |||
| func verifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, saltLen int) error { | |||
| nBits := pub.N.BitLen() | |||
| if len(sig) != (nBits+7)/8 { | |||
| return ErrVerification | |||
| } | |||
| s := new(big.Int).SetBytes(sig) | |||
| m := encrypt(new(big.Int), pub, s) | |||
| emBits := nBits - 1 | |||
| emLen := (emBits + 7) / 8 | |||
| if emLen < len(m.Bytes()) { | |||
| return ErrVerification | |||
| } | |||
| em := make([]byte, emLen) | |||
| copyWithLeftPad(em, m.Bytes()) | |||
| if saltLen == PSSSaltLengthEqualsHash { | |||
| saltLen = hash.Size() | |||
| } | |||
| return emsaPSSVerify(hashed, em, emBits, saltLen, hash.New()) | |||
| } | |||
| @@ -0,0 +1,646 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // Package rsa implements RSA encryption as specified in PKCS#1. | |||
| // | |||
| // RSA is a single, fundamental operation that is used in this package to | |||
| // implement either public-key encryption or public-key signatures. | |||
| // | |||
| // The original specification for encryption and signatures with RSA is PKCS#1 | |||
| // and the terms "RSA encryption" and "RSA signatures" by default refer to | |||
| // PKCS#1 version 1.5. However, that specification has flaws and new designs | |||
| // should use version two, usually called by just OAEP and PSS, where | |||
| // possible. | |||
| // | |||
| // Two sets of interfaces are included in this package. When a more abstract | |||
| // interface isn't neccessary, there are functions for encrypting/decrypting | |||
| // with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract | |||
| // over the public-key primitive, the PrivateKey struct implements the | |||
| // Decrypter and Signer interfaces from the crypto package. | |||
| package rsa | |||
| import ( | |||
| "crypto" | |||
| "crypto/rand" | |||
| "crypto/subtle" | |||
| "errors" | |||
| "hash" | |||
| "io" | |||
| "math/big" | |||
| ) | |||
| var bigZero = big.NewInt(0) | |||
| var bigOne = big.NewInt(1) | |||
| // A PublicKey represents the public part of an RSA key. | |||
| type PublicKey struct { | |||
| N *big.Int // modulus | |||
| E int64 // public exponent | |||
| } | |||
| // OAEPOptions is an interface for passing options to OAEP decryption using the | |||
| // crypto.Decrypter interface. | |||
| type OAEPOptions struct { | |||
| // Hash is the hash function that will be used when generating the mask. | |||
| Hash crypto.Hash | |||
| // Label is an arbitrary byte string that must be equal to the value | |||
| // used when encrypting. | |||
| Label []byte | |||
| } | |||
| var ( | |||
| errPublicModulus = errors.New("crypto/rsa: missing public modulus") | |||
| errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small") | |||
| errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large") | |||
| ) | |||
| // checkPub sanity checks the public key before we use it. | |||
| // We require pub.E to fit into a 32-bit integer so that we | |||
| // do not have different behavior depending on whether | |||
| // int is 32 or 64 bits. See also | |||
| // http://www.imperialviolet.org/2012/03/16/rsae.html. | |||
| func checkPub(pub *PublicKey) error { | |||
| if pub.N == nil { | |||
| return errPublicModulus | |||
| } | |||
| if pub.E < 2 { | |||
| return errPublicExponentSmall | |||
| } | |||
| if pub.E > 1<<63-1 { | |||
| return errPublicExponentLarge | |||
| } | |||
| return nil | |||
| } | |||
| // A PrivateKey represents an RSA key | |||
| type PrivateKey struct { | |||
| PublicKey // public part. | |||
| D *big.Int // private exponent | |||
| Primes []*big.Int // prime factors of N, has >= 2 elements. | |||
| // Precomputed contains precomputed values that speed up private | |||
| // operations, if available. | |||
| Precomputed PrecomputedValues | |||
| } | |||
| // Public returns the public key corresponding to priv. | |||
| func (priv *PrivateKey) Public() crypto.PublicKey { | |||
| return &priv.PublicKey | |||
| } | |||
| // Sign signs msg with priv, reading randomness from rand. If opts is a | |||
| // *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will | |||
| // be used. This method is intended to support keys where the private part is | |||
| // kept in, for example, a hardware module. Common uses should use the Sign* | |||
| // functions in this package. | |||
| func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { | |||
| if pssOpts, ok := opts.(*PSSOptions); ok { | |||
| return SignPSS(rand, priv, pssOpts.Hash, msg, pssOpts) | |||
| } | |||
| return SignPKCS1v15(rand, priv, opts.HashFunc(), msg) | |||
| } | |||
| // Decrypt decrypts ciphertext with priv. If opts is nil or of type | |||
| // *PKCS1v15DecryptOptions then PKCS#1 v1.5 decryption is performed. Otherwise | |||
| // opts must have type *OAEPOptions and OAEP decryption is done. | |||
| func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) { | |||
| if opts == nil { | |||
| return DecryptPKCS1v15(rand, priv, ciphertext) | |||
| } | |||
| switch opts := opts.(type) { | |||
| case *OAEPOptions: | |||
| return DecryptOAEP(opts.Hash.New(), rand, priv, ciphertext, opts.Label) | |||
| case *PKCS1v15DecryptOptions: | |||
| if l := opts.SessionKeyLen; l > 0 { | |||
| plaintext = make([]byte, l) | |||
| if _, err := io.ReadFull(rand, plaintext); err != nil { | |||
| return nil, err | |||
| } | |||
| if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil { | |||
| return nil, err | |||
| } | |||
| return plaintext, nil | |||
| } else { | |||
| return DecryptPKCS1v15(rand, priv, ciphertext) | |||
| } | |||
| default: | |||
| return nil, errors.New("crypto/rsa: invalid options for Decrypt") | |||
| } | |||
| } | |||
| type PrecomputedValues struct { | |||
| Dp, Dq *big.Int // D mod (P-1) (or mod Q-1) | |||
| Qinv *big.Int // Q^-1 mod P | |||
| // CRTValues is used for the 3rd and subsequent primes. Due to a | |||
| // historical accident, the CRT for the first two primes is handled | |||
| // differently in PKCS#1 and interoperability is sufficiently | |||
| // important that we mirror this. | |||
| CRTValues []CRTValue | |||
| } | |||
| // CRTValue contains the precomputed Chinese remainder theorem values. | |||
| type CRTValue struct { | |||
| Exp *big.Int // D mod (prime-1). | |||
| Coeff *big.Int // R·Coeff ≡ 1 mod Prime. | |||
| R *big.Int // product of primes prior to this (inc p and q). | |||
| } | |||
| // Validate performs basic sanity checks on the key. | |||
| // It returns nil if the key is valid, or else an error describing a problem. | |||
| func (priv *PrivateKey) Validate() error { | |||
| if err := checkPub(&priv.PublicKey); err != nil { | |||
| return err | |||
| } | |||
| // Check that Πprimes == n. | |||
| modulus := new(big.Int).Set(bigOne) | |||
| for _, prime := range priv.Primes { | |||
| // Any primes ≤ 1 will cause divide-by-zero panics later. | |||
| if prime.Cmp(bigOne) <= 0 { | |||
| return errors.New("crypto/rsa: invalid prime value") | |||
| } | |||
| modulus.Mul(modulus, prime) | |||
| } | |||
| if modulus.Cmp(priv.N) != 0 { | |||
| return errors.New("crypto/rsa: invalid modulus") | |||
| } | |||
| // Check that de ≡ 1 mod p-1, for each prime. | |||
| // This implies that e is coprime to each p-1 as e has a multiplicative | |||
| // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) = | |||
| // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 | |||
| // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required. | |||
| congruence := new(big.Int) | |||
| de := new(big.Int).SetInt64(int64(priv.E)) | |||
| de.Mul(de, priv.D) | |||
| for _, prime := range priv.Primes { | |||
| pminus1 := new(big.Int).Sub(prime, bigOne) | |||
| congruence.Mod(de, pminus1) | |||
| if congruence.Cmp(bigOne) != 0 { | |||
| return errors.New("crypto/rsa: invalid exponents") | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| // GenerateKey generates an RSA keypair of the given bit size using the | |||
| // random source random (for example, crypto/rand.Reader). | |||
| func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) { | |||
| return GenerateMultiPrimeKey(random, 2, bits) | |||
| } | |||
| // GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit | |||
| // size and the given random source, as suggested in [1]. Although the public | |||
| // keys are compatible (actually, indistinguishable) from the 2-prime case, | |||
| // the private keys are not. Thus it may not be possible to export multi-prime | |||
| // private keys in certain formats or to subsequently import them into other | |||
| // code. | |||
| // | |||
| // Table 1 in [2] suggests maximum numbers of primes for a given size. | |||
| // | |||
| // [1] US patent 4405829 (1972, expired) | |||
| // [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf | |||
| func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err error) { | |||
| priv = new(PrivateKey) | |||
| priv.E = 65537 | |||
| if nprimes < 2 { | |||
| return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2") | |||
| } | |||
| primes := make([]*big.Int, nprimes) | |||
| NextSetOfPrimes: | |||
| for { | |||
| todo := bits | |||
| // crypto/rand should set the top two bits in each prime. | |||
| // Thus each prime has the form | |||
| // p_i = 2^bitlen(p_i) × 0.11... (in base 2). | |||
| // And the product is: | |||
| // P = 2^todo × α | |||
| // where α is the product of nprimes numbers of the form 0.11... | |||
| // | |||
| // If α < 1/2 (which can happen for nprimes > 2), we need to | |||
| // shift todo to compensate for lost bits: the mean value of 0.11... | |||
| // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2 | |||
| // will give good results. | |||
| if nprimes >= 7 { | |||
| todo += (nprimes - 2) / 5 | |||
| } | |||
| for i := 0; i < nprimes; i++ { | |||
| primes[i], err = rand.Prime(random, todo/(nprimes-i)) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| todo -= primes[i].BitLen() | |||
| } | |||
| // Make sure that primes is pairwise unequal. | |||
| for i, prime := range primes { | |||
| for j := 0; j < i; j++ { | |||
| if prime.Cmp(primes[j]) == 0 { | |||
| continue NextSetOfPrimes | |||
| } | |||
| } | |||
| } | |||
| n := new(big.Int).Set(bigOne) | |||
| totient := new(big.Int).Set(bigOne) | |||
| pminus1 := new(big.Int) | |||
| for _, prime := range primes { | |||
| n.Mul(n, prime) | |||
| pminus1.Sub(prime, bigOne) | |||
| totient.Mul(totient, pminus1) | |||
| } | |||
| if n.BitLen() != bits { | |||
| // This should never happen for nprimes == 2 because | |||
| // crypto/rand should set the top two bits in each prime. | |||
| // For nprimes > 2 we hope it does not happen often. | |||
| continue NextSetOfPrimes | |||
| } | |||
| g := new(big.Int) | |||
| priv.D = new(big.Int) | |||
| y := new(big.Int) | |||
| e := big.NewInt(int64(priv.E)) | |||
| g.GCD(priv.D, y, e, totient) | |||
| if g.Cmp(bigOne) == 0 { | |||
| if priv.D.Sign() < 0 { | |||
| priv.D.Add(priv.D, totient) | |||
| } | |||
| priv.Primes = primes | |||
| priv.N = n | |||
| break | |||
| } | |||
| } | |||
| priv.Precompute() | |||
| return | |||
| } | |||
| // incCounter increments a four byte, big-endian counter. | |||
| func incCounter(c *[4]byte) { | |||
| if c[3]++; c[3] != 0 { | |||
| return | |||
| } | |||
| if c[2]++; c[2] != 0 { | |||
| return | |||
| } | |||
| if c[1]++; c[1] != 0 { | |||
| return | |||
| } | |||
| c[0]++ | |||
| } | |||
| // mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function | |||
| // specified in PKCS#1 v2.1. | |||
| func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { | |||
| var counter [4]byte | |||
| var digest []byte | |||
| done := 0 | |||
| for done < len(out) { | |||
| hash.Write(seed) | |||
| hash.Write(counter[0:4]) | |||
| digest = hash.Sum(digest[:0]) | |||
| hash.Reset() | |||
| for i := 0; i < len(digest) && done < len(out); i++ { | |||
| out[done] ^= digest[i] | |||
| done++ | |||
| } | |||
| incCounter(&counter) | |||
| } | |||
| } | |||
| // ErrMessageTooLong is returned when attempting to encrypt a message which is | |||
| // too large for the size of the public key. | |||
| var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size") | |||
| func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int { | |||
| e := big.NewInt(int64(pub.E)) | |||
| c.Exp(m, e, pub.N) | |||
| return c | |||
| } | |||
| // EncryptOAEP encrypts the given message with RSA-OAEP. | |||
| // | |||
| // OAEP is parameterised by a hash function that is used as a random oracle. | |||
| // Encryption and decryption of a given message must use the same hash function | |||
| // and sha256.New() is a reasonable choice. | |||
| // | |||
| // The random parameter is used as a source of entropy to ensure that | |||
| // encrypting the same message twice doesn't result in the same ciphertext. | |||
| // | |||
| // The label parameter may contain arbitrary data that will not be encrypted, | |||
| // but which gives important context to the message. For example, if a given | |||
| // public key is used to decrypt two types of messages then distinct label | |||
| // values could be used to ensure that a ciphertext for one purpose cannot be | |||
| // used for another by an attacker. If not required it can be empty. | |||
| // | |||
| // The message must be no longer than the length of the public modulus less | |||
| // twice the hash length plus 2. | |||
| func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) { | |||
| if err := checkPub(pub); err != nil { | |||
| return nil, err | |||
| } | |||
| hash.Reset() | |||
| k := (pub.N.BitLen() + 7) / 8 | |||
| if len(msg) > k-2*hash.Size()-2 { | |||
| err = ErrMessageTooLong | |||
| return | |||
| } | |||
| hash.Write(label) | |||
| lHash := hash.Sum(nil) | |||
| hash.Reset() | |||
| em := make([]byte, k) | |||
| seed := em[1 : 1+hash.Size()] | |||
| db := em[1+hash.Size():] | |||
| copy(db[0:hash.Size()], lHash) | |||
| db[len(db)-len(msg)-1] = 1 | |||
| copy(db[len(db)-len(msg):], msg) | |||
| _, err = io.ReadFull(random, seed) | |||
| if err != nil { | |||
| return | |||
| } | |||
| mgf1XOR(db, hash, seed) | |||
| mgf1XOR(seed, hash, db) | |||
| m := new(big.Int) | |||
| m.SetBytes(em) | |||
| c := encrypt(new(big.Int), pub, m) | |||
| out = c.Bytes() | |||
| if len(out) < k { | |||
| // If the output is too small, we need to left-pad with zeros. | |||
| t := make([]byte, k) | |||
| copy(t[k-len(out):], out) | |||
| out = t | |||
| } | |||
| return | |||
| } | |||
| // ErrDecryption represents a failure to decrypt a message. | |||
| // It is deliberately vague to avoid adaptive attacks. | |||
| var ErrDecryption = errors.New("crypto/rsa: decryption error") | |||
| // ErrVerification represents a failure to verify a signature. | |||
| // It is deliberately vague to avoid adaptive attacks. | |||
| var ErrVerification = errors.New("crypto/rsa: verification error") | |||
| // modInverse returns ia, the inverse of a in the multiplicative group of prime | |||
| // order n. It requires that a be a member of the group (i.e. less than n). | |||
| func modInverse(a, n *big.Int) (ia *big.Int, ok bool) { | |||
| g := new(big.Int) | |||
| x := new(big.Int) | |||
| y := new(big.Int) | |||
| g.GCD(x, y, a, n) | |||
| if g.Cmp(bigOne) != 0 { | |||
| // In this case, a and n aren't coprime and we cannot calculate | |||
| // the inverse. This happens because the values of n are nearly | |||
| // prime (being the product of two primes) rather than truly | |||
| // prime. | |||
| return | |||
| } | |||
| if x.Cmp(bigOne) < 0 { | |||
| // 0 is not the multiplicative inverse of any element so, if x | |||
| // < 1, then x is negative. | |||
| x.Add(x, n) | |||
| } | |||
| return x, true | |||
| } | |||
| // Precompute performs some calculations that speed up private key operations | |||
| // in the future. | |||
| func (priv *PrivateKey) Precompute() { | |||
| if priv.Precomputed.Dp != nil { | |||
| return | |||
| } | |||
| priv.Precomputed.Dp = new(big.Int).Sub(priv.Primes[0], bigOne) | |||
| priv.Precomputed.Dp.Mod(priv.D, priv.Precomputed.Dp) | |||
| priv.Precomputed.Dq = new(big.Int).Sub(priv.Primes[1], bigOne) | |||
| priv.Precomputed.Dq.Mod(priv.D, priv.Precomputed.Dq) | |||
| priv.Precomputed.Qinv = new(big.Int).ModInverse(priv.Primes[1], priv.Primes[0]) | |||
| r := new(big.Int).Mul(priv.Primes[0], priv.Primes[1]) | |||
| priv.Precomputed.CRTValues = make([]CRTValue, len(priv.Primes)-2) | |||
| for i := 2; i < len(priv.Primes); i++ { | |||
| prime := priv.Primes[i] | |||
| values := &priv.Precomputed.CRTValues[i-2] | |||
| values.Exp = new(big.Int).Sub(prime, bigOne) | |||
| values.Exp.Mod(priv.D, values.Exp) | |||
| values.R = new(big.Int).Set(r) | |||
| values.Coeff = new(big.Int).ModInverse(r, prime) | |||
| r.Mul(r, prime) | |||
| } | |||
| } | |||
| // decrypt performs an RSA decryption, resulting in a plaintext integer. If a | |||
| // random source is given, RSA blinding is used. | |||
| func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { | |||
| // TODO(agl): can we get away with reusing blinds? | |||
| if c.Cmp(priv.N) > 0 { | |||
| err = ErrDecryption | |||
| return | |||
| } | |||
| var ir *big.Int | |||
| if random != nil { | |||
| // Blinding enabled. Blinding involves multiplying c by r^e. | |||
| // Then the decryption operation performs (m^e * r^e)^d mod n | |||
| // which equals mr mod n. The factor of r can then be removed | |||
| // by multiplying by the multiplicative inverse of r. | |||
| var r *big.Int | |||
| for { | |||
| r, err = rand.Int(random, priv.N) | |||
| if err != nil { | |||
| return | |||
| } | |||
| if r.Cmp(bigZero) == 0 { | |||
| r = bigOne | |||
| } | |||
| var ok bool | |||
| ir, ok = modInverse(r, priv.N) | |||
| if ok { | |||
| break | |||
| } | |||
| } | |||
| bigE := big.NewInt(int64(priv.E)) | |||
| rpowe := new(big.Int).Exp(r, bigE, priv.N) | |||
| cCopy := new(big.Int).Set(c) | |||
| cCopy.Mul(cCopy, rpowe) | |||
| cCopy.Mod(cCopy, priv.N) | |||
| c = cCopy | |||
| } | |||
| if priv.Precomputed.Dp == nil { | |||
| m = new(big.Int).Exp(c, priv.D, priv.N) | |||
| } else { | |||
| // We have the precalculated values needed for the CRT. | |||
| m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0]) | |||
| m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1]) | |||
| m.Sub(m, m2) | |||
| if m.Sign() < 0 { | |||
| m.Add(m, priv.Primes[0]) | |||
| } | |||
| m.Mul(m, priv.Precomputed.Qinv) | |||
| m.Mod(m, priv.Primes[0]) | |||
| m.Mul(m, priv.Primes[1]) | |||
| m.Add(m, m2) | |||
| for i, values := range priv.Precomputed.CRTValues { | |||
| prime := priv.Primes[2+i] | |||
| m2.Exp(c, values.Exp, prime) | |||
| m2.Sub(m2, m) | |||
| m2.Mul(m2, values.Coeff) | |||
| m2.Mod(m2, prime) | |||
| if m2.Sign() < 0 { | |||
| m2.Add(m2, prime) | |||
| } | |||
| m2.Mul(m2, values.R) | |||
| m.Add(m, m2) | |||
| } | |||
| } | |||
| if ir != nil { | |||
| // Unblind. | |||
| m.Mul(m, ir) | |||
| m.Mod(m, priv.N) | |||
| } | |||
| return | |||
| } | |||
| func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { | |||
| m, err = decrypt(random, priv, c) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| // In order to defend against errors in the CRT computation, m^e is | |||
| // calculated, which should match the original ciphertext. | |||
| check := encrypt(new(big.Int), &priv.PublicKey, m) | |||
| if c.Cmp(check) != 0 { | |||
| return nil, errors.New("rsa: internal error") | |||
| } | |||
| return m, nil | |||
| } | |||
| // DecryptOAEP decrypts ciphertext using RSA-OAEP. | |||
| // OAEP is parameterised by a hash function that is used as a random oracle. | |||
| // Encryption and decryption of a given message must use the same hash function | |||
| // and sha256.New() is a reasonable choice. | |||
| // | |||
| // The random parameter, if not nil, is used to blind the private-key operation | |||
| // and avoid timing side-channel attacks. Blinding is purely internal to this | |||
| // function – the random data need not match that used when encrypting. | |||
| // | |||
| // The label parameter must match the value given when encrypting. See | |||
| // EncryptOAEP for details. | |||
| func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) { | |||
| if err := checkPub(&priv.PublicKey); err != nil { | |||
| return nil, err | |||
| } | |||
| k := (priv.N.BitLen() + 7) / 8 | |||
| if len(ciphertext) > k || | |||
| k < hash.Size()*2+2 { | |||
| err = ErrDecryption | |||
| return | |||
| } | |||
| c := new(big.Int).SetBytes(ciphertext) | |||
| m, err := decrypt(random, priv, c) | |||
| if err != nil { | |||
| return | |||
| } | |||
| hash.Write(label) | |||
| lHash := hash.Sum(nil) | |||
| hash.Reset() | |||
| // Converting the plaintext number to bytes will strip any | |||
| // leading zeros so we may have to left pad. We do this unconditionally | |||
| // to avoid leaking timing information. (Although we still probably | |||
| // leak the number of leading zeros. It's not clear that we can do | |||
| // anything about this.) | |||
| em := leftPad(m.Bytes(), k) | |||
| firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) | |||
| seed := em[1 : hash.Size()+1] | |||
| db := em[hash.Size()+1:] | |||
| mgf1XOR(seed, hash, db) | |||
| mgf1XOR(db, hash, seed) | |||
| lHash2 := db[0:hash.Size()] | |||
| // We have to validate the plaintext in constant time in order to avoid | |||
| // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal | |||
| // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1 | |||
| // v2.0. In J. Kilian, editor, Advances in Cryptology. | |||
| lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2) | |||
| // The remainder of the plaintext must be zero or more 0x00, followed | |||
| // by 0x01, followed by the message. | |||
| // lookingForIndex: 1 iff we are still looking for the 0x01 | |||
| // index: the offset of the first 0x01 byte | |||
| // invalid: 1 iff we saw a non-zero byte before the 0x01. | |||
| var lookingForIndex, index, invalid int | |||
| lookingForIndex = 1 | |||
| rest := db[hash.Size():] | |||
| for i := 0; i < len(rest); i++ { | |||
| equals0 := subtle.ConstantTimeByteEq(rest[i], 0) | |||
| equals1 := subtle.ConstantTimeByteEq(rest[i], 1) | |||
| index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index) | |||
| lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex) | |||
| invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid) | |||
| } | |||
| if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 { | |||
| err = ErrDecryption | |||
| return | |||
| } | |||
| msg = rest[index+1:] | |||
| return | |||
| } | |||
| // leftPad returns a new slice of length size. The contents of input are right | |||
| // aligned in the new slice. | |||
| func leftPad(input []byte, size int) (out []byte) { | |||
| n := len(input) | |||
| if n > size { | |||
| n = size | |||
| } | |||
| out = make([]byte, size) | |||
| copy(out[len(out)-n:], input) | |||
| return | |||
| } | |||
| @@ -1,637 +0,0 @@ | |||
| // Copyright 2011 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package openpgp | |||
| import ( | |||
| "crypto/rsa" | |||
| "io" | |||
| "time" | |||
| "golang.org/x/crypto/openpgp/armor" | |||
| "golang.org/x/crypto/openpgp/errors" | |||
| "golang.org/x/crypto/openpgp/packet" | |||
| ) | |||
| // PublicKeyType is the armor type for a PGP public key. | |||
| var PublicKeyType = "PGP PUBLIC KEY BLOCK" | |||
| // PrivateKeyType is the armor type for a PGP private key. | |||
| var PrivateKeyType = "PGP PRIVATE KEY BLOCK" | |||
| // An Entity represents the components of an OpenPGP key: a primary public key | |||
| // (which must be a signing key), one or more identities claimed by that key, | |||
| // and zero or more subkeys, which may be encryption keys. | |||
| type Entity struct { | |||
| PrimaryKey *packet.PublicKey | |||
| PrivateKey *packet.PrivateKey | |||
| Identities map[string]*Identity // indexed by Identity.Name | |||
| Revocations []*packet.Signature | |||
| Subkeys []Subkey | |||
| } | |||
| // An Identity represents an identity claimed by an Entity and zero or more | |||
| // assertions by other entities about that claim. | |||
| type Identity struct { | |||
| Name string // by convention, has the form "Full Name (comment) <email@example.com>" | |||
| UserId *packet.UserId | |||
| SelfSignature *packet.Signature | |||
| Signatures []*packet.Signature | |||
| } | |||
| // A Subkey is an additional public key in an Entity. Subkeys can be used for | |||
| // encryption. | |||
| type Subkey struct { | |||
| PublicKey *packet.PublicKey | |||
| PrivateKey *packet.PrivateKey | |||
| Sig *packet.Signature | |||
| } | |||
| // A Key identifies a specific public key in an Entity. This is either the | |||
| // Entity's primary key or a subkey. | |||
| type Key struct { | |||
| Entity *Entity | |||
| PublicKey *packet.PublicKey | |||
| PrivateKey *packet.PrivateKey | |||
| SelfSignature *packet.Signature | |||
| } | |||
| // A KeyRing provides access to public and private keys. | |||
| type KeyRing interface { | |||
| // KeysById returns the set of keys that have the given key id. | |||
| KeysById(id uint64) []Key | |||
| // KeysByIdAndUsage returns the set of keys with the given id | |||
| // that also meet the key usage given by requiredUsage. | |||
| // The requiredUsage is expressed as the bitwise-OR of | |||
| // packet.KeyFlag* values. | |||
| KeysByIdUsage(id uint64, requiredUsage byte) []Key | |||
| // DecryptionKeys returns all private keys that are valid for | |||
| // decryption. | |||
| DecryptionKeys() []Key | |||
| } | |||
| // primaryIdentity returns the Identity marked as primary or the first identity | |||
| // if none are so marked. | |||
| func (e *Entity) primaryIdentity() *Identity { | |||
| var firstIdentity *Identity | |||
| for _, ident := range e.Identities { | |||
| if firstIdentity == nil { | |||
| firstIdentity = ident | |||
| } | |||
| if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { | |||
| return ident | |||
| } | |||
| } | |||
| return firstIdentity | |||
| } | |||
| // encryptionKey returns the best candidate Key for encrypting a message to the | |||
| // given Entity. | |||
| func (e *Entity) encryptionKey(now time.Time) (Key, bool) { | |||
| candidateSubkey := -1 | |||
| // Iterate the keys to find the newest key | |||
| var maxTime time.Time | |||
| for i, subkey := range e.Subkeys { | |||
| if subkey.Sig.FlagsValid && | |||
| subkey.Sig.FlagEncryptCommunications && | |||
| subkey.PublicKey.PubKeyAlgo.CanEncrypt() && | |||
| !subkey.Sig.KeyExpired(now) && | |||
| (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { | |||
| candidateSubkey = i | |||
| maxTime = subkey.Sig.CreationTime | |||
| } | |||
| } | |||
| if candidateSubkey != -1 { | |||
| subkey := e.Subkeys[candidateSubkey] | |||
| return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true | |||
| } | |||
| // If we don't have any candidate subkeys for encryption and | |||
| // the primary key doesn't have any usage metadata then we | |||
| // assume that the primary key is ok. Or, if the primary key is | |||
| // marked as ok to encrypt to, then we can obviously use it. | |||
| i := e.primaryIdentity() | |||
| if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && | |||
| e.PrimaryKey.PubKeyAlgo.CanEncrypt() && | |||
| !i.SelfSignature.KeyExpired(now) { | |||
| return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true | |||
| } | |||
| // This Entity appears to be signing only. | |||
| return Key{}, false | |||
| } | |||
| // signingKey return the best candidate Key for signing a message with this | |||
| // Entity. | |||
| func (e *Entity) signingKey(now time.Time) (Key, bool) { | |||
| candidateSubkey := -1 | |||
| for i, subkey := range e.Subkeys { | |||
| if subkey.Sig.FlagsValid && | |||
| subkey.Sig.FlagSign && | |||
| subkey.PublicKey.PubKeyAlgo.CanSign() && | |||
| !subkey.Sig.KeyExpired(now) { | |||
| candidateSubkey = i | |||
| break | |||
| } | |||
| } | |||
| if candidateSubkey != -1 { | |||
| subkey := e.Subkeys[candidateSubkey] | |||
| return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true | |||
| } | |||
| // If we have no candidate subkey then we assume that it's ok to sign | |||
| // with the primary key. | |||
| i := e.primaryIdentity() | |||
| if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign && | |||
| !i.SelfSignature.KeyExpired(now) { | |||
| return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true | |||
| } | |||
| return Key{}, false | |||
| } | |||
| // An EntityList contains one or more Entities. | |||
| type EntityList []*Entity | |||
| // KeysById returns the set of keys that have the given key id. | |||
| func (el EntityList) KeysById(id uint64) (keys []Key) { | |||
| for _, e := range el { | |||
| if e.PrimaryKey.KeyId == id { | |||
| var selfSig *packet.Signature | |||
| for _, ident := range e.Identities { | |||
| if selfSig == nil { | |||
| selfSig = ident.SelfSignature | |||
| } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { | |||
| selfSig = ident.SelfSignature | |||
| break | |||
| } | |||
| } | |||
| keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig}) | |||
| } | |||
| for _, subKey := range e.Subkeys { | |||
| if subKey.PublicKey.KeyId == id { | |||
| keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig}) | |||
| } | |||
| } | |||
| } | |||
| return | |||
| } | |||
| // KeysByIdAndUsage returns the set of keys with the given id that also meet | |||
| // the key usage given by requiredUsage. The requiredUsage is expressed as | |||
| // the bitwise-OR of packet.KeyFlag* values. | |||
| func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) { | |||
| for _, key := range el.KeysById(id) { | |||
| if len(key.Entity.Revocations) > 0 { | |||
| continue | |||
| } | |||
| if key.SelfSignature.RevocationReason != nil { | |||
| continue | |||
| } | |||
| if key.SelfSignature.FlagsValid && requiredUsage != 0 { | |||
| var usage byte | |||
| if key.SelfSignature.FlagCertify { | |||
| usage |= packet.KeyFlagCertify | |||
| } | |||
| if key.SelfSignature.FlagSign { | |||
| usage |= packet.KeyFlagSign | |||
| } | |||
| if key.SelfSignature.FlagEncryptCommunications { | |||
| usage |= packet.KeyFlagEncryptCommunications | |||
| } | |||
| if key.SelfSignature.FlagEncryptStorage { | |||
| usage |= packet.KeyFlagEncryptStorage | |||
| } | |||
| if usage&requiredUsage != requiredUsage { | |||
| continue | |||
| } | |||
| } | |||
| keys = append(keys, key) | |||
| } | |||
| return | |||
| } | |||
| // DecryptionKeys returns all private keys that are valid for decryption. | |||
| func (el EntityList) DecryptionKeys() (keys []Key) { | |||
| for _, e := range el { | |||
| for _, subKey := range e.Subkeys { | |||
| if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) { | |||
| keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig}) | |||
| } | |||
| } | |||
| } | |||
| return | |||
| } | |||
| // ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file. | |||
| func ReadArmoredKeyRing(r io.Reader) (EntityList, error) { | |||
| block, err := armor.Decode(r) | |||
| if err == io.EOF { | |||
| return nil, errors.InvalidArgumentError("no armored data found") | |||
| } | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if block.Type != PublicKeyType && block.Type != PrivateKeyType { | |||
| return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type) | |||
| } | |||
| return ReadKeyRing(block.Body) | |||
| } | |||
| // ReadKeyRing reads one or more public/private keys. Unsupported keys are | |||
| // ignored as long as at least a single valid key is found. | |||
| func ReadKeyRing(r io.Reader) (el EntityList, err error) { | |||
| packets := packet.NewReader(r) | |||
| var lastUnsupportedError error | |||
| for { | |||
| var e *Entity | |||
| e, err = ReadEntity(packets) | |||
| if err != nil { | |||
| // TODO: warn about skipped unsupported/unreadable keys | |||
| if _, ok := err.(errors.UnsupportedError); ok { | |||
| lastUnsupportedError = err | |||
| err = readToNextPublicKey(packets) | |||
| } else if _, ok := err.(errors.StructuralError); ok { | |||
| // Skip unreadable, badly-formatted keys | |||
| lastUnsupportedError = err | |||
| err = readToNextPublicKey(packets) | |||
| } | |||
| if err == io.EOF { | |||
| err = nil | |||
| break | |||
| } | |||
| if err != nil { | |||
| el = nil | |||
| break | |||
| } | |||
| } else { | |||
| el = append(el, e) | |||
| } | |||
| } | |||
| if len(el) == 0 && err == nil { | |||
| err = lastUnsupportedError | |||
| } | |||
| return | |||
| } | |||
| // readToNextPublicKey reads packets until the start of the entity and leaves | |||
| // the first packet of the new entity in the Reader. | |||
| func readToNextPublicKey(packets *packet.Reader) (err error) { | |||
| var p packet.Packet | |||
| for { | |||
| p, err = packets.Next() | |||
| if err == io.EOF { | |||
| return | |||
| } else if err != nil { | |||
| if _, ok := err.(errors.UnsupportedError); ok { | |||
| err = nil | |||
| continue | |||
| } | |||
| return | |||
| } | |||
| if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey { | |||
| packets.Unread(p) | |||
| return | |||
| } | |||
| } | |||
| } | |||
| // ReadEntity reads an entity (public key, identities, subkeys etc) from the | |||
| // given Reader. | |||
| func ReadEntity(packets *packet.Reader) (*Entity, error) { | |||
| e := new(Entity) | |||
| e.Identities = make(map[string]*Identity) | |||
| p, err := packets.Next() | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| var ok bool | |||
| if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok { | |||
| if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { | |||
| packets.Unread(p) | |||
| return nil, errors.StructuralError("first packet was not a public/private key") | |||
| } else { | |||
| e.PrimaryKey = &e.PrivateKey.PublicKey | |||
| } | |||
| } | |||
| if !e.PrimaryKey.PubKeyAlgo.CanSign() { | |||
| return nil, errors.StructuralError("primary key cannot be used for signatures") | |||
| } | |||
| var current *Identity | |||
| var revocations []*packet.Signature | |||
| EachPacket: | |||
| for { | |||
| p, err := packets.Next() | |||
| if err == io.EOF { | |||
| break | |||
| } else if err != nil { | |||
| return nil, err | |||
| } | |||
| switch pkt := p.(type) { | |||
| case *packet.UserId: | |||
| current = new(Identity) | |||
| current.Name = pkt.Id | |||
| current.UserId = pkt | |||
| e.Identities[pkt.Id] = current | |||
| for { | |||
| p, err = packets.Next() | |||
| if err == io.EOF { | |||
| return nil, io.ErrUnexpectedEOF | |||
| } else if err != nil { | |||
| return nil, err | |||
| } | |||
| sig, ok := p.(*packet.Signature) | |||
| if !ok { | |||
| return nil, errors.StructuralError("user ID packet not followed by self-signature") | |||
| } | |||
| if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { | |||
| if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { | |||
| return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error()) | |||
| } | |||
| current.SelfSignature = sig | |||
| break | |||
| } | |||
| current.Signatures = append(current.Signatures, sig) | |||
| } | |||
| case *packet.Signature: | |||
| if pkt.SigType == packet.SigTypeKeyRevocation { | |||
| revocations = append(revocations, pkt) | |||
| } else if pkt.SigType == packet.SigTypeDirectSignature { | |||
| // TODO: RFC4880 5.2.1 permits signatures | |||
| // directly on keys (eg. to bind additional | |||
| // revocation keys). | |||
| } else if current == nil { | |||
| return nil, errors.StructuralError("signature packet found before user id packet") | |||
| } else { | |||
| current.Signatures = append(current.Signatures, pkt) | |||
| } | |||
| case *packet.PrivateKey: | |||
| if pkt.IsSubkey == false { | |||
| packets.Unread(p) | |||
| break EachPacket | |||
| } | |||
| err = addSubkey(e, packets, &pkt.PublicKey, pkt) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| case *packet.PublicKey: | |||
| if pkt.IsSubkey == false { | |||
| packets.Unread(p) | |||
| break EachPacket | |||
| } | |||
| err = addSubkey(e, packets, pkt, nil) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| default: | |||
| // we ignore unknown packets | |||
| } | |||
| } | |||
| if len(e.Identities) == 0 { | |||
| return nil, errors.StructuralError("entity without any identities") | |||
| } | |||
| for _, revocation := range revocations { | |||
| err = e.PrimaryKey.VerifyRevocationSignature(revocation) | |||
| if err == nil { | |||
| e.Revocations = append(e.Revocations, revocation) | |||
| } else { | |||
| // TODO: RFC 4880 5.2.3.15 defines revocation keys. | |||
| return nil, errors.StructuralError("revocation signature signed by alternate key") | |||
| } | |||
| } | |||
| return e, nil | |||
| } | |||
| func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { | |||
| var subKey Subkey | |||
| subKey.PublicKey = pub | |||
| subKey.PrivateKey = priv | |||
| p, err := packets.Next() | |||
| if err == io.EOF { | |||
| return io.ErrUnexpectedEOF | |||
| } | |||
| if err != nil { | |||
| return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||
| } | |||
| var ok bool | |||
| subKey.Sig, ok = p.(*packet.Signature) | |||
| if !ok { | |||
| return errors.StructuralError("subkey packet not followed by signature") | |||
| } | |||
| if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation { | |||
| return errors.StructuralError("subkey signature with wrong type") | |||
| } | |||
| err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig) | |||
| if err != nil { | |||
| return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||
| } | |||
| e.Subkeys = append(e.Subkeys, subKey) | |||
| return nil | |||
| } | |||
| const defaultRSAKeyBits = 2048 | |||
| // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a | |||
| // single identity composed of the given full name, comment and email, any of | |||
| // which may be empty but must not contain any of "()<>\x00". | |||
| // If config is nil, sensible defaults will be used. | |||
| func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { | |||
| currentTime := config.Now() | |||
| bits := defaultRSAKeyBits | |||
| if config != nil && config.RSABits != 0 { | |||
| bits = config.RSABits | |||
| } | |||
| uid := packet.NewUserId(name, comment, email) | |||
| if uid == nil { | |||
| return nil, errors.InvalidArgumentError("user id field contained invalid characters") | |||
| } | |||
| signingPriv, err := rsa.GenerateKey(config.Random(), bits) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| encryptingPriv, err := rsa.GenerateKey(config.Random(), bits) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| e := &Entity{ | |||
| PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey), | |||
| PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv), | |||
| Identities: make(map[string]*Identity), | |||
| } | |||
| isPrimaryId := true | |||
| e.Identities[uid.Id] = &Identity{ | |||
| Name: uid.Name, | |||
| UserId: uid, | |||
| SelfSignature: &packet.Signature{ | |||
| CreationTime: currentTime, | |||
| SigType: packet.SigTypePositiveCert, | |||
| PubKeyAlgo: packet.PubKeyAlgoRSA, | |||
| Hash: config.Hash(), | |||
| IsPrimaryId: &isPrimaryId, | |||
| FlagsValid: true, | |||
| FlagSign: true, | |||
| FlagCertify: true, | |||
| IssuerKeyId: &e.PrimaryKey.KeyId, | |||
| }, | |||
| } | |||
| // If the user passes in a DefaultHash via packet.Config, | |||
| // set the PreferredHash for the SelfSignature. | |||
| if config != nil && config.DefaultHash != 0 { | |||
| e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)} | |||
| } | |||
| e.Subkeys = make([]Subkey, 1) | |||
| e.Subkeys[0] = Subkey{ | |||
| PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), | |||
| PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv), | |||
| Sig: &packet.Signature{ | |||
| CreationTime: currentTime, | |||
| SigType: packet.SigTypeSubkeyBinding, | |||
| PubKeyAlgo: packet.PubKeyAlgoRSA, | |||
| Hash: config.Hash(), | |||
| FlagsValid: true, | |||
| FlagEncryptStorage: true, | |||
| FlagEncryptCommunications: true, | |||
| IssuerKeyId: &e.PrimaryKey.KeyId, | |||
| }, | |||
| } | |||
| e.Subkeys[0].PublicKey.IsSubkey = true | |||
| e.Subkeys[0].PrivateKey.IsSubkey = true | |||
| return e, nil | |||
| } | |||
| // SerializePrivate serializes an Entity, including private key material, to | |||
| // the given Writer. For now, it must only be used on an Entity returned from | |||
| // NewEntity. | |||
| // If config is nil, sensible defaults will be used. | |||
| func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { | |||
| err = e.PrivateKey.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| for _, ident := range e.Identities { | |||
| err = ident.UserId.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) | |||
| if err != nil { | |||
| return | |||
| } | |||
| err = ident.SelfSignature.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| } | |||
| for _, subkey := range e.Subkeys { | |||
| err = subkey.PrivateKey.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | |||
| if err != nil { | |||
| return | |||
| } | |||
| err = subkey.Sig.Serialize(w) | |||
| if err != nil { | |||
| return | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| // Serialize writes the public part of the given Entity to w. (No private | |||
| // key material will be output). | |||
| func (e *Entity) Serialize(w io.Writer) error { | |||
| err := e.PrimaryKey.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| for _, ident := range e.Identities { | |||
| err = ident.UserId.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| err = ident.SelfSignature.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| for _, sig := range ident.Signatures { | |||
| err = sig.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| for _, subkey := range e.Subkeys { | |||
| err = subkey.PublicKey.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| err = subkey.Sig.Serialize(w) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| // SignIdentity adds a signature to e, from signer, attesting that identity is | |||
| // associated with e. The provided identity must already be an element of | |||
| // e.Identities and the private key of signer must have been decrypted if | |||
| // necessary. | |||
| // If config is nil, sensible defaults will be used. | |||
| func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error { | |||
| if signer.PrivateKey == nil { | |||
| return errors.InvalidArgumentError("signing Entity must have a private key") | |||
| } | |||
| if signer.PrivateKey.Encrypted { | |||
| return errors.InvalidArgumentError("signing Entity's private key must be decrypted") | |||
| } | |||
| ident, ok := e.Identities[identity] | |||
| if !ok { | |||
| return errors.InvalidArgumentError("given identity string not found in Entity") | |||
| } | |||
| sig := &packet.Signature{ | |||
| SigType: packet.SigTypeGenericCert, | |||
| PubKeyAlgo: signer.PrivateKey.PubKeyAlgo, | |||
| Hash: config.Hash(), | |||
| CreationTime: config.Now(), | |||
| IssuerKeyId: &signer.PrivateKey.KeyId, | |||
| } | |||
| if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil { | |||
| return err | |||
| } | |||
| ident.Signatures = append(ident.Signatures, sig) | |||
| return nil | |||
| } | |||
| @@ -515,6 +515,84 @@ | |||
| "revision": "b2c7a7da5b2995941048f60146e67702a292e468", | |||
| "revisionTime": "2016-02-12T04:00:40Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "VJk3rOWfxEV9Ilig5lgzH1qg8Ss=", | |||
| "path": "github.com/keybase/go-crypto/brainpool", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "rnRjEJs5luF+DIXp2J6LFcQk8Gg=", | |||
| "path": "github.com/keybase/go-crypto/cast5", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "F5++ZQS5Vt7hd6lxPCKTffvph1A=", | |||
| "path": "github.com/keybase/go-crypto/curve25519", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "IvrDXwIixB5yPPbo6tq1/1cSn78=", | |||
| "path": "github.com/keybase/go-crypto/ed25519", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "4+fslB6pCbplNq4viy6CrOkkY6Y=", | |||
| "path": "github.com/keybase/go-crypto/ed25519/internal/edwards25519", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "fgFlkfkaotUjBVhJik2979oCeJw=", | |||
| "path": "github.com/keybase/go-crypto/openpgp", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "+spfcEChljh3yeIg4K/xHOQ2pVM=", | |||
| "path": "github.com/keybase/go-crypto/openpgp/armor", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "nWhmwjBJqPSvkCWqaap2Z9EiS1k=", | |||
| "path": "github.com/keybase/go-crypto/openpgp/ecdh", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "uxXG9IC/XF8jwwvZUbW65+x8/+M=", | |||
| "path": "github.com/keybase/go-crypto/openpgp/elgamal", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "EyUf82Yknzc75m8RcA21CNQINw0=", | |||
| "path": "github.com/keybase/go-crypto/openpgp/errors", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "y16ATKgHL/k6rQZqdXP1sIAJxE0=", | |||
| "path": "github.com/keybase/go-crypto/openpgp/packet", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "BGDxg1Xtsz0DSPzdQGJLLQqfYc8=", | |||
| "path": "github.com/keybase/go-crypto/openpgp/s2k", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "rE3pp7b3gfcmBregzpIvN5IdFhY=", | |||
| "path": "github.com/keybase/go-crypto/rsa", | |||
| "revision": "00ac4db533f63ef97576cbc7b07939ff7daf7329", | |||
| "revisionTime": "2017-06-05T14:56:57Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "fh+CcgeUUsnuwSORHYWg0ycbp+4=", | |||
| "path": "github.com/klauspost/compress/flate", | |||
| @@ -1182,12 +1260,6 @@ | |||
| "revision": "2c050d2dae5345c417db301f11fda6fbf5ad0f0a", | |||
| "revisionTime": "2016-09-14T08:04:27Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=", | |||
| "path": "golang.org/x/crypto/cast5", | |||
| "revision": "b8a2a83acfe6e6770b75de42d5ff4c67596675c0", | |||
| "revisionTime": "2017-01-13T19:21:00Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "dwOedwBJ1EIK9+S3t108Bx054Y8=", | |||
| "path": "golang.org/x/crypto/curve25519", | |||
| @@ -1212,42 +1284,6 @@ | |||
| "revision": "ede567c8e044a5913dad1d1af3696d9da953104c", | |||
| "revisionTime": "2016-11-04T19:41:44Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "IIhFTrLlmlc6lEFSitqi4aw2lw0=", | |||
| "path": "golang.org/x/crypto/openpgp", | |||
| "revision": "b8a2a83acfe6e6770b75de42d5ff4c67596675c0", | |||
| "revisionTime": "2017-01-13T19:21:00Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "olOKkhrdkYQHZ0lf1orrFQPQrv4=", | |||
| "path": "golang.org/x/crypto/openpgp/armor", | |||
| "revision": "b8a2a83acfe6e6770b75de42d5ff4c67596675c0", | |||
| "revisionTime": "2017-01-13T19:21:00Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "eo/KtdjieJQXH7Qy+faXFcF70ME=", | |||
| "path": "golang.org/x/crypto/openpgp/elgamal", | |||
| "revision": "b8a2a83acfe6e6770b75de42d5ff4c67596675c0", | |||
| "revisionTime": "2017-01-13T19:21:00Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "rlxVSaGgqdAgwblsErxTxIfuGfg=", | |||
| "path": "golang.org/x/crypto/openpgp/errors", | |||
| "revision": "b8a2a83acfe6e6770b75de42d5ff4c67596675c0", | |||
| "revisionTime": "2017-01-13T19:21:00Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "LWdaR8Q9yn6eBCcnGl0HvJRDUBE=", | |||
| "path": "golang.org/x/crypto/openpgp/packet", | |||
| "revision": "b8a2a83acfe6e6770b75de42d5ff4c67596675c0", | |||
| "revisionTime": "2017-01-13T19:21:00Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "s2qT4UwvzBSkzXuiuMkowif1Olw=", | |||
| "path": "golang.org/x/crypto/openpgp/s2k", | |||
| "revision": "b8a2a83acfe6e6770b75de42d5ff4c67596675c0", | |||
| "revisionTime": "2017-01-13T19:21:00Z" | |||
| }, | |||
| { | |||
| "checksumSHA1": "1MGpGDQqnUoRpv7VEcQrXOBydXE=", | |||
| "path": "golang.org/x/crypto/pbkdf2", | |||