Switch to keybase go-crypto (for some elliptic curve key) + test (#1925)
* 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
tokarchuk/v1.17
parent
5e92b82ac6
commit
274149dd14
@ -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)) |
||||||
|
} |
@ -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 |
File diff suppressed because it is too large
Load Diff
@ -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 |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
1771
vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
1771
vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
File diff suppressed because it is too large
Load Diff
@ -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) |
||||||
|
} |
@ -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 |
||||||
|
} |
@ -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 |
||||||
|
} |
@ -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 ./... |
@ -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-----
|
||||||
|
+`
|
@ -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 |
|
||||||
} |
|
Loading…
Reference in new issue