github.com/jmhodges/levigo v1.0.0 // indirect | github.com/jmhodges/levigo v1.0.0 // indirect | ||||
github.com/joho/godotenv v1.3.0 // indirect | github.com/joho/godotenv v1.3.0 // indirect | ||||
github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 | github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 | ||||
github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6 | |||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 | |||||
github.com/klauspost/compress v1.9.2 | github.com/klauspost/compress v1.9.2 | ||||
github.com/lafriks/xormstore v1.3.2 | github.com/lafriks/xormstore v1.3.2 | ||||
github.com/lib/pq v1.2.0 | github.com/lib/pq v1.2.0 |
cloud.google.com/go v0.45.0/go.mod h1:452BcPOeI9AZfbvDw0Tbo7D32wA+WX9WME8AZwMEDZU= | cloud.google.com/go v0.45.0/go.mod h1:452BcPOeI9AZfbvDw0Tbo7D32wA+WX9WME8AZwMEDZU= | ||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= | ||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= | ||||
gitea.com/lunny/levelqueue v0.1.0 h1:7wMk0VH6mvKN6vZEZCy9nUDgRmdPLgeNrm1NkW8EHNk= | |||||
gitea.com/lunny/levelqueue v0.1.0/go.mod h1:G7hVb908t0Bl0uk7zGSg14fyzNtxgtD9Shf04wkMK7s= | |||||
gitea.com/lunny/levelqueue v0.2.0 h1:lR/5EAwQtFcn5YvPEkNMw0p9pAy2/O2nSP5ImECLA2E= | gitea.com/lunny/levelqueue v0.2.0 h1:lR/5EAwQtFcn5YvPEkNMw0p9pAy2/O2nSP5ImECLA2E= | ||||
gitea.com/lunny/levelqueue v0.2.0/go.mod h1:G7hVb908t0Bl0uk7zGSg14fyzNtxgtD9Shf04wkMK7s= | gitea.com/lunny/levelqueue v0.2.0/go.mod h1:G7hVb908t0Bl0uk7zGSg14fyzNtxgtD9Shf04wkMK7s= | ||||
gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b h1:vXt85uYV17KURaUlhU7v4GbCShkqRZDSfo0TkC0YCjQ= | gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b h1:vXt85uYV17KURaUlhU7v4GbCShkqRZDSfo0TkC0YCjQ= | ||||
github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= | github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= | ||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= | ||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | ||||
github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6 h1:9mszGwKDxHEY2cy+9XxCQKWIfkGPSAEFrcN8ghzyAKg= | |||||
github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= | |||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+4tLukHoB9iqHOu3LmLhRmgUxZo6Vp4= | |||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= | |||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | ||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||||
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY= | github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY= | ||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= | ||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= | github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= | ||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= | github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= | ||||
github.com/src-d/enry v1.7.3 h1:jG2fmEaQaURh0qqU/sn82BRzVa6d4EVHJIw6gc98bak= | |||||
github.com/src-d/enry/v2 v2.1.0 h1:z1L8t+B8bh3mmjPkJrgOTnVRpFGmTPJsplHX9wAn6BI= | github.com/src-d/enry/v2 v2.1.0 h1:z1L8t+B8bh3mmjPkJrgOTnVRpFGmTPJsplHX9wAn6BI= | ||||
github.com/src-d/enry/v2 v2.1.0/go.mod h1:qQeCMRwzMF3ckeGr+h0tJLdxXnq+NVZsIDMELj0t028= | github.com/src-d/enry/v2 v2.1.0/go.mod h1:qQeCMRwzMF3ckeGr+h0tJLdxXnq+NVZsIDMELj0t028= | ||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= | github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= |
// Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common | // Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common | ||||
// OpenPGP cipher. | // OpenPGP cipher. | ||||
package cast5 | |||||
package cast5 // import "github.com/keybase/go-crypto/cast5" | |||||
import "errors" | import "errors" | ||||
// 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: https://bench.cr.yp.to/supercop.html | |||||
#define REDMASK51 0x0007FFFFFFFFFFFF |
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
// This code was translated into a form compatible with 6a from the public | // This code was translated into a form compatible with 6a from the public | ||||
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | |||||
// +build amd64,!gccgo,!appengine | // +build amd64,!gccgo,!appengine | ||||
DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF | |||||
GLOBL ·REDMASK51(SB), 8, $8 | |||||
// These constants cannot be encoded in non-MOVQ immediates. | |||||
// We access them directly from memory instead. | |||||
DATA ·_121666_213(SB)/8, $996687872 | DATA ·_121666_213(SB)/8, $996687872 | ||||
GLOBL ·_121666_213(SB), 8, $8 | GLOBL ·_121666_213(SB), 8, $8 |
// Use of this source code is governed by a BSD-style | // Use of this source code is governed by a BSD-style | ||||
// license that can be found in the LICENSE file. | // 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 | // +build amd64,!gccgo,!appengine | ||||
// func cswap(inout *[5]uint64, v uint64) | |||||
// func cswap(inout *[4][5]uint64, v uint64) | |||||
TEXT ·cswap(SB),7,$0 | TEXT ·cswap(SB),7,$0 | ||||
MOVQ inout+0(FP),DI | MOVQ inout+0(FP),DI | ||||
MOVQ v+8(FP),SI | 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 | |||||
SUBQ $1, SI | |||||
NOTQ SI | |||||
MOVQ SI, X15 | |||||
PSHUFD $0x44, X15, X15 | |||||
MOVOU 0(DI), X0 | |||||
MOVOU 16(DI), X2 | |||||
MOVOU 32(DI), X4 | |||||
MOVOU 48(DI), X6 | |||||
MOVOU 64(DI), X8 | |||||
MOVOU 80(DI), X1 | |||||
MOVOU 96(DI), X3 | |||||
MOVOU 112(DI), X5 | |||||
MOVOU 128(DI), X7 | |||||
MOVOU 144(DI), X9 | |||||
MOVO X1, X10 | |||||
MOVO X3, X11 | |||||
MOVO X5, X12 | |||||
MOVO X7, X13 | |||||
MOVO X9, X14 | |||||
PXOR X0, X10 | |||||
PXOR X2, X11 | |||||
PXOR X4, X12 | |||||
PXOR X6, X13 | |||||
PXOR X8, X14 | |||||
PAND X15, X10 | |||||
PAND X15, X11 | |||||
PAND X15, X12 | |||||
PAND X15, X13 | |||||
PAND X15, X14 | |||||
PXOR X10, X0 | |||||
PXOR X10, X1 | |||||
PXOR X11, X2 | |||||
PXOR X11, X3 | |||||
PXOR X12, X4 | |||||
PXOR X12, X5 | |||||
PXOR X13, X6 | |||||
PXOR X13, X7 | |||||
PXOR X14, X8 | |||||
PXOR X14, X9 | |||||
MOVOU X0, 0(DI) | |||||
MOVOU X2, 16(DI) | |||||
MOVOU X4, 32(DI) | |||||
MOVOU X6, 48(DI) | |||||
MOVOU X8, 64(DI) | |||||
MOVOU X1, 80(DI) | |||||
MOVOU X3, 96(DI) | |||||
MOVOU X5, 112(DI) | |||||
MOVOU X7, 128(DI) | |||||
MOVOU X9, 144(DI) | |||||
RET | RET |
// Use of this source code is governed by a BSD-style | // Use of this source code is governed by a BSD-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
// We have a implementation in amd64 assembly so this code is only run on | |||||
// We have an implementation in amd64 assembly so this code is only run on | |||||
// non-amd64 platforms. The amd64 assembly does not support gccgo. | // non-amd64 platforms. The amd64 assembly does not support gccgo. | ||||
// +build !amd64 gccgo appengine | // +build !amd64 gccgo appengine | ||||
package curve25519 | package curve25519 | ||||
import ( | |||||
"encoding/binary" | |||||
) | |||||
// This code is a port of the public domain, "ref10" implementation of | // This code is a port of the public domain, "ref10" implementation of | ||||
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein. | // curve25519 from SUPERCOP 20130419 by D. J. Bernstein. | ||||
// | // | ||||
// Preconditions: b in {0,1}. | // Preconditions: b in {0,1}. | ||||
func feCSwap(f, g *fieldElement, b int32) { | func feCSwap(f, g *fieldElement, b int32) { | ||||
var x fieldElement | |||||
b = -b | b = -b | ||||
for i := range x { | |||||
x[i] = b & (f[i] ^ g[i]) | |||||
} | |||||
for i := range f { | for i := range f { | ||||
f[i] ^= x[i] | |||||
} | |||||
for i := range g { | |||||
g[i] ^= x[i] | |||||
t := b & (f[i] ^ g[i]) | |||||
f[i] ^= t | |||||
g[i] ^= t | |||||
} | } | ||||
} | } | ||||
// load4 reads a 32-bit, little-endian value from in. | // load4 reads a 32-bit, little-endian value from in. | ||||
func load4(in []byte) int64 { | 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 | |||||
return int64(binary.LittleEndian.Uint32(in)) | |||||
} | } | ||||
func feFromBytes(dst *fieldElement, src *[32]byte) { | func feFromBytes(dst *fieldElement, src *[32]byte) { |
// Curve 25519 multiplication functions expect scalars in reverse | // Curve 25519 multiplication functions expect scalars in reverse | ||||
// order than PGP. To keep the curve25519Curve type consistent | // order than PGP. To keep the curve25519Curve type consistent | ||||
// with other curves, we reverse it here. | // with other curves, we reverse it here. | ||||
for i, j := 0, len(src)-1; j >= 0; i, j = i+1, j-1 { | |||||
for i, j := 0, len(src)-1; j >= 0 && i < len(dst); i, j = i+1, j-1 { | |||||
dst[i] = src[j] | dst[i] = src[j] | ||||
} | } | ||||
} | } | ||||
func copyTruncate(dst []byte, src []byte) { | |||||
lenDst, lenSrc := len(dst), len(src) | |||||
if lenDst == lenSrc { | |||||
copy(dst, src) | |||||
} else if lenDst > lenSrc { | |||||
copy(dst[lenDst-lenSrc:lenDst], src) | |||||
} else if lenDst < lenSrc { | |||||
copy(dst, src[:lenDst]) | |||||
} | |||||
} | |||||
func (cv25519Curve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) { | func (cv25519Curve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) { | ||||
// Assume y1 is 0 with cv25519. | // Assume y1 is 0 with cv25519. | ||||
var dst [32]byte | var dst [32]byte | ||||
var x1Bytes [32]byte | var x1Bytes [32]byte | ||||
var scalarBytes [32]byte | var scalarBytes [32]byte | ||||
copy(x1Bytes[:], x1.Bytes()[:32]) | |||||
copyReverse(scalarBytes[:], scalar[:32]) | |||||
copyTruncate(x1Bytes[:], x1.Bytes()) | |||||
copyReverse(scalarBytes[:], scalar) | |||||
scalarMult(&dst, &scalarBytes, &x1Bytes) | scalarMult(&dst, &scalarBytes, &x1Bytes) | ||||
ret[0] = 0x40 | ret[0] = 0x40 | ||||
xBytes := x.Bytes() | xBytes := x.Bytes() | ||||
copy(ret[1+byteLen-len(xBytes):], xBytes) | |||||
copyTruncate(ret[1:], xBytes) | |||||
return ret | return ret | ||||
} | } | ||||
// Some code relies on these parameters being available for | // Some code relies on these parameters being available for | ||||
// checking Curve coordinate length. They should not be used | // checking Curve coordinate length. They should not be used | ||||
// directly for any calculations. | // 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.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 | cv25519.BitSize = 256 | ||||
} | } | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
// Package curve25519 provides an implementation of scalar multiplication on | // Package curve25519 provides an implementation of scalar multiplication on | ||||
// the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html | |||||
package curve25519 | |||||
// the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html | |||||
package curve25519 // import "github.com/keybase/go-crypto/curve25519" | |||||
// basePoint is the x coordinate of the generator of the curve. | // 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} | 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} |
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
// This code was translated into a form compatible with 6a from the public | // This code was translated into a form compatible with 6a from the public | ||||
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | |||||
// +build amd64,!gccgo,!appengine | // +build amd64,!gccgo,!appengine | ||||
#include "const_amd64.h" | |||||
// func freeze(inout *[5]uint64) | // func freeze(inout *[5]uint64) | ||||
TEXT ·freeze(SB),7,$96-8 | |||||
TEXT ·freeze(SB),7,$0-8 | |||||
MOVQ inout+0(FP), DI | 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 0(DI),SI | ||||
MOVQ 8(DI),DX | MOVQ 8(DI),DX | ||||
MOVQ 16(DI),CX | MOVQ 16(DI),CX | ||||
MOVQ 24(DI),R8 | MOVQ 24(DI),R8 | ||||
MOVQ 32(DI),R9 | MOVQ 32(DI),R9 | ||||
MOVQ ·REDMASK51(SB),AX | |||||
MOVQ $REDMASK51,AX | |||||
MOVQ AX,R10 | MOVQ AX,R10 | ||||
SUBQ $18,R10 | SUBQ $18,R10 | ||||
MOVQ $3,R11 | MOVQ $3,R11 | ||||
MOVQ CX,16(DI) | MOVQ CX,16(DI) | ||||
MOVQ R8,24(DI) | MOVQ R8,24(DI) | ||||
MOVQ R9,32(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 | RET |
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
// This code was translated into a form compatible with 6a from the public | // This code was translated into a form compatible with 6a from the public | ||||
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | |||||
// +build amd64,!gccgo,!appengine | // +build amd64,!gccgo,!appengine | ||||
#include "const_amd64.h" | |||||
// func mul(dest, a, b *[5]uint64) | // func mul(dest, a, b *[5]uint64) | ||||
TEXT ·mul(SB),0,$128-24 | |||||
TEXT ·mul(SB),0,$16-24 | |||||
MOVQ dest+0(FP), DI | MOVQ dest+0(FP), DI | ||||
MOVQ a+8(FP), SI | MOVQ a+8(FP), SI | ||||
MOVQ b+16(FP), DX | 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 DX,CX | ||||
MOVQ 24(SI),DX | MOVQ 24(SI),DX | ||||
IMUL3Q $19,DX,AX | IMUL3Q $19,DX,AX | ||||
MOVQ AX,64(SP) | |||||
MOVQ AX,0(SP) | |||||
MULQ 16(CX) | MULQ 16(CX) | ||||
MOVQ AX,R8 | MOVQ AX,R8 | ||||
MOVQ DX,R9 | MOVQ DX,R9 | ||||
MOVQ 32(SI),DX | MOVQ 32(SI),DX | ||||
IMUL3Q $19,DX,AX | IMUL3Q $19,DX,AX | ||||
MOVQ AX,72(SP) | |||||
MOVQ AX,8(SP) | |||||
MULQ 8(CX) | MULQ 8(CX) | ||||
ADDQ AX,R8 | ADDQ AX,R8 | ||||
ADCQ DX,R9 | ADCQ DX,R9 | ||||
MULQ 8(CX) | MULQ 8(CX) | ||||
ADDQ AX,BX | ADDQ AX,BX | ||||
ADCQ DX,BP | ADCQ DX,BP | ||||
MOVQ 64(SP),AX | |||||
MOVQ 0(SP),AX | |||||
MULQ 24(CX) | MULQ 24(CX) | ||||
ADDQ AX,R10 | ADDQ AX,R10 | ||||
ADCQ DX,R11 | ADCQ DX,R11 | ||||
MOVQ 64(SP),AX | |||||
MOVQ 0(SP),AX | |||||
MULQ 32(CX) | MULQ 32(CX) | ||||
ADDQ AX,R12 | ADDQ AX,R12 | ||||
ADCQ DX,R13 | ADCQ DX,R13 | ||||
MULQ 0(CX) | MULQ 0(CX) | ||||
ADDQ AX,BX | ADDQ AX,BX | ||||
ADCQ DX,BP | ADCQ DX,BP | ||||
MOVQ 72(SP),AX | |||||
MOVQ 8(SP),AX | |||||
MULQ 16(CX) | MULQ 16(CX) | ||||
ADDQ AX,R10 | ADDQ AX,R10 | ||||
ADCQ DX,R11 | ADCQ DX,R11 | ||||
MOVQ 72(SP),AX | |||||
MOVQ 8(SP),AX | |||||
MULQ 24(CX) | MULQ 24(CX) | ||||
ADDQ AX,R12 | ADDQ AX,R12 | ||||
ADCQ DX,R13 | ADCQ DX,R13 | ||||
MOVQ 72(SP),AX | |||||
MOVQ 8(SP),AX | |||||
MULQ 32(CX) | MULQ 32(CX) | ||||
ADDQ AX,R14 | ADDQ AX,R14 | ||||
ADCQ DX,R15 | ADCQ DX,R15 | ||||
MOVQ ·REDMASK51(SB),SI | |||||
MOVQ $REDMASK51,SI | |||||
SHLQ $13,R9:R8 | SHLQ $13,R9:R8 | ||||
ANDQ SI,R8 | ANDQ SI,R8 | ||||
SHLQ $13,R11:R10 | SHLQ $13,R11:R10 | ||||
MOVQ R9,16(DI) | MOVQ R9,16(DI) | ||||
MOVQ AX,24(DI) | MOVQ AX,24(DI) | ||||
MOVQ R10,32(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 | RET |
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
// This code was translated into a form compatible with 6a from the public | // This code was translated into a form compatible with 6a from the public | ||||
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html | |||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | |||||
// +build amd64,!gccgo,!appengine | // +build amd64,!gccgo,!appengine | ||||
#include "const_amd64.h" | |||||
// func square(out, in *[5]uint64) | // func square(out, in *[5]uint64) | ||||
TEXT ·square(SB),7,$96-16 | |||||
TEXT ·square(SB),7,$0-16 | |||||
MOVQ out+0(FP), DI | MOVQ out+0(FP), DI | ||||
MOVQ in+8(FP), SI | 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 | MOVQ 0(SI),AX | ||||
MULQ 0(SI) | MULQ 0(SI) | ||||
MOVQ AX,CX | MOVQ AX,CX | ||||
MULQ 32(SI) | MULQ 32(SI) | ||||
ADDQ AX,R13 | ADDQ AX,R13 | ||||
ADCQ DX,R14 | ADCQ DX,R14 | ||||
MOVQ ·REDMASK51(SB),SI | |||||
MOVQ $REDMASK51,SI | |||||
SHLQ $13,R8:CX | SHLQ $13,R8:CX | ||||
ANDQ SI,CX | ANDQ SI,CX | ||||
SHLQ $13,R10:R9 | SHLQ $13,R10:R9 | ||||
MOVQ R9,16(DI) | MOVQ R9,16(DI) | ||||
MOVQ AX,24(DI) | MOVQ AX,24(DI) | ||||
MOVQ R10,32(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 | RET |
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
// Package ed25519 implements the Ed25519 signature algorithm. See | // Package ed25519 implements the Ed25519 signature algorithm. See | ||||
// http://ed25519.cr.yp.to/. | |||||
// https://ed25519.cr.yp.to/. | |||||
// | // | ||||
// These functions are also compatible with the “Ed25519” function defined in | // These functions are also compatible with the “Ed25519” function defined in | ||||
// https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05. | |||||
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key | |||||
// representation includes a public key suffix to make multiple signing | |||||
// operations with the same key more efficient. This package refers to the RFC | |||||
// 8032 private key as the “seed”. | |||||
package ed25519 | package ed25519 | ||||
// This code is a port of the public domain, “ref10” implementation of ed25519 | // This code is a port of the public domain, “ref10” implementation of ed25519 | ||||
// from SUPERCOP. | // from SUPERCOP. | ||||
import ( | import ( | ||||
"bytes" | |||||
"crypto" | "crypto" | ||||
cryptorand "crypto/rand" | cryptorand "crypto/rand" | ||||
"crypto/sha512" | "crypto/sha512" | ||||
"crypto/subtle" | |||||
"errors" | "errors" | ||||
"io" | "io" | ||||
"strconv" | "strconv" | ||||
PrivateKeySize = 64 | PrivateKeySize = 64 | ||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package. | // SignatureSize is the size, in bytes, of signatures generated and verified by this package. | ||||
SignatureSize = 64 | SignatureSize = 64 | ||||
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. | |||||
SeedSize = 32 | |||||
) | ) | ||||
// PublicKey is the type of Ed25519 public keys. | // PublicKey is the type of Ed25519 public keys. | ||||
return PublicKey(publicKey) | return PublicKey(publicKey) | ||||
} | } | ||||
// Seed returns the private key seed corresponding to priv. It is provided for | |||||
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds | |||||
// in this package. | |||||
func (priv PrivateKey) Seed() []byte { | |||||
seed := make([]byte, SeedSize) | |||||
copy(seed, priv[:32]) | |||||
return seed | |||||
} | |||||
// Sign signs the given message with priv. | // Sign signs the given message with priv. | ||||
// Ed25519 performs two passes over messages to be signed and therefore cannot | // Ed25519 performs two passes over messages to be signed and therefore cannot | ||||
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to | // handle pre-hashed messages. Thus opts.HashFunc() must return zero to | ||||
// GenerateKey generates a public/private key pair using entropy from rand. | // GenerateKey generates a public/private key pair using entropy from rand. | ||||
// If rand is nil, crypto/rand.Reader will be used. | // If rand is nil, crypto/rand.Reader will be used. | ||||
func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) { | |||||
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { | |||||
if rand == nil { | if rand == nil { | ||||
rand = cryptorand.Reader | rand = cryptorand.Reader | ||||
} | } | ||||
privateKey = make([]byte, PrivateKeySize) | |||||
publicKey = make([]byte, PublicKeySize) | |||||
_, err = io.ReadFull(rand, privateKey[:32]) | |||||
if err != nil { | |||||
seed := make([]byte, SeedSize) | |||||
if _, err := io.ReadFull(rand, seed); err != nil { | |||||
return nil, nil, err | return nil, nil, err | ||||
} | } | ||||
digest := sha512.Sum512(privateKey[:32]) | |||||
privateKey := NewKeyFromSeed(seed) | |||||
publicKey := make([]byte, PublicKeySize) | |||||
copy(publicKey, privateKey[32:]) | |||||
return publicKey, privateKey, nil | |||||
} | |||||
// NewKeyFromSeed calculates a private key from a seed. It will panic if | |||||
// len(seed) is not SeedSize. This function is provided for interoperability | |||||
// with RFC 8032. RFC 8032's private keys correspond to seeds in this | |||||
// package. | |||||
func NewKeyFromSeed(seed []byte) PrivateKey { | |||||
if l := len(seed); l != SeedSize { | |||||
panic("ed25519: bad seed length: " + strconv.Itoa(l)) | |||||
} | |||||
digest := sha512.Sum512(seed) | |||||
digest[0] &= 248 | digest[0] &= 248 | ||||
digest[31] &= 127 | digest[31] &= 127 | ||||
digest[31] |= 64 | digest[31] |= 64 | ||||
var publicKeyBytes [32]byte | var publicKeyBytes [32]byte | ||||
A.ToBytes(&publicKeyBytes) | A.ToBytes(&publicKeyBytes) | ||||
privateKey := make([]byte, PrivateKeySize) | |||||
copy(privateKey, seed) | |||||
copy(privateKey[32:], publicKeyBytes[:]) | copy(privateKey[32:], publicKeyBytes[:]) | ||||
copy(publicKey, publicKeyBytes[:]) | |||||
return publicKey, privateKey, nil | |||||
return privateKey | |||||
} | } | ||||
// Sign signs the message with privateKey and returns a signature. It will | // Sign signs the message with privateKey and returns a signature. It will | ||||
edwards25519.ScReduce(&hReduced, &digest) | edwards25519.ScReduce(&hReduced, &digest) | ||||
var R edwards25519.ProjectiveGroupElement | var R edwards25519.ProjectiveGroupElement | ||||
var b [32]byte | |||||
copy(b[:], sig[32:]) | |||||
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b) | |||||
var s [32]byte | |||||
copy(s[:], sig[32:]) | |||||
// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in | |||||
// the range [0, order) in order to prevent signature malleability. | |||||
if !edwards25519.ScMinimal(&s) { | |||||
return false | |||||
} | |||||
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s) | |||||
var checkR [32]byte | var checkR [32]byte | ||||
R.ToBytes(&checkR) | R.ToBytes(&checkR) | ||||
return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1 | |||||
return bytes.Equal(sig[:32], checkR[:]) | |||||
} | } |
package edwards25519 | package edwards25519 | ||||
import "encoding/binary" | |||||
// This code is a port of the public domain, “ref10” implementation of ed25519 | // This code is a port of the public domain, “ref10” implementation of ed25519 | ||||
// from SUPERCOP. | // from SUPERCOP. | ||||
out[30] = byte(s11 >> 9) | out[30] = byte(s11 >> 9) | ||||
out[31] = byte(s11 >> 17) | out[31] = byte(s11 >> 17) | ||||
} | } | ||||
// order is the order of Curve25519 in little-endian form. | |||||
var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000} | |||||
// ScMinimal returns true if the given scalar is less than the order of the | |||||
// curve. | |||||
func ScMinimal(scalar *[32]byte) bool { | |||||
for i := 3; ; i-- { | |||||
v := binary.LittleEndian.Uint64(scalar[i*8:]) | |||||
if v > order[i] { | |||||
return false | |||||
} else if v < order[i] { | |||||
break | |||||
} else if i == 0 { | |||||
return false | |||||
} | |||||
} | |||||
return true | |||||
} |
"bufio" | "bufio" | ||||
"bytes" | "bytes" | ||||
"encoding/base64" | "encoding/base64" | ||||
"fmt" | |||||
"io" | "io" | ||||
"strings" | "strings" | ||||
"unicode" | "unicode" | ||||
return | return | ||||
} | } | ||||
line, _, err := l.in.ReadLine() | |||||
line, isPrefix, err := l.in.ReadLine() | |||||
if err != nil { | if err != nil { | ||||
return | return | ||||
} | } | ||||
// Entry-level cleanup, just trim spaces. | |||||
line = bytes.TrimFunc(line, ourIsSpace) | line = bytes.TrimFunc(line, ourIsSpace) | ||||
if len(line) == 5 && line[0] == '=' { | |||||
// This is the checksum line | |||||
lineWithChecksum := false | |||||
foldedChecksum := false | |||||
if !isPrefix && len(line) >= 5 && line[len(line)-5] == '=' && line[len(line)-4] != '=' { | |||||
// This is the checksum line. Checksum should appear on separate line, | |||||
// but some bundles don't have a newline between main payload and the | |||||
// checksum, and we try to support that. | |||||
// `=` is not a base64 character with the exception of padding, and the | |||||
// padding can only be 2 characters long at most ("=="), so we can | |||||
// safely assume that 5 characters starting with `=` at the end of the | |||||
// line can't be a valid ending of a base64 stream. In other words, `=` | |||||
// at position len-5 in base64 stream can never be a valid part of that | |||||
// stream. | |||||
// Checksum can never appear if isPrefix is true - that is, when | |||||
// ReadLine returned non-final part of some line because it was longer | |||||
// than its buffer. | |||||
if l.crc != nil { | |||||
// Error out early if there are multiple checksums. | |||||
return 0, ArmorCorrupt | |||||
} | |||||
var expectedBytes [3]byte | var expectedBytes [3]byte | ||||
var m int | var m int | ||||
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:]) | |||||
if m != 3 || err != nil { | |||||
return | |||||
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[len(line)-4:]) | |||||
if err != nil { | |||||
return 0, fmt.Errorf("error decoding CRC: %s", err.Error()) | |||||
} else if m != 3 { | |||||
return 0, fmt.Errorf("error decoding CRC: wrong size CRC") | |||||
} | } | ||||
crc := uint32(expectedBytes[0])<<16 | | crc := uint32(expectedBytes[0])<<16 | | ||||
uint32(expectedBytes[1])<<8 | | uint32(expectedBytes[1])<<8 | | ||||
uint32(expectedBytes[2]) | uint32(expectedBytes[2]) | ||||
l.crc = &crc | l.crc = &crc | ||||
line = line[:len(line)-5] | |||||
lineWithChecksum = true | |||||
// If we've found a checksum but there is still data left, we don't | |||||
// want to enter the "looking for armor end" loop, we still need to | |||||
// return the leftover data to the reader. | |||||
foldedChecksum = len(line) > 0 | |||||
// At this point, `line` contains leftover data or "" (if checksum | |||||
// was on separate line.) | |||||
} | |||||
expectArmorEnd := false | |||||
if l.crc != nil && !foldedChecksum { | |||||
// "looking for armor end" loop | |||||
// We have a checksum, and we are now reading what comes afterwards. | |||||
// Skip all empty lines until we see something and we except it to be | |||||
// ArmorEnd at this point. | |||||
// This loop is not entered if there is more data *before* the CRC | |||||
// suffix (if the CRC is not on separate line). | |||||
for { | for { | ||||
line, _, err = l.in.ReadLine() | |||||
if err != nil && err != io.EOF { | |||||
return | |||||
} | |||||
if len(strings.TrimSpace(string(line))) > 0 { | if len(strings.TrimSpace(string(line))) > 0 { | ||||
break | break | ||||
} | } | ||||
lineWithChecksum = false | |||||
line, _, err = l.in.ReadLine() | |||||
if err == io.EOF { | |||||
break | |||||
} | |||||
if err != nil { | |||||
return | |||||
} | |||||
} | } | ||||
if !bytes.HasPrefix(line, armorEnd) { | |||||
return 0, ArmorCorrupt | |||||
} | |||||
l.eof = true | |||||
return 0, io.EOF | |||||
expectArmorEnd = true | |||||
} | } | ||||
if bytes.HasPrefix(line, armorEnd) { | if bytes.HasPrefix(line, armorEnd) { | ||||
// Unexpected ending, there was no checksum. | |||||
if lineWithChecksum { | |||||
// ArmorEnd and checksum at the same line? | |||||
return 0, ArmorCorrupt | |||||
} | |||||
l.eof = true | l.eof = true | ||||
l.crc = nil | |||||
return 0, io.EOF | return 0, io.EOF | ||||
} else if expectArmorEnd { | |||||
// We wanted armorEnd but didn't see one. | |||||
return 0, ArmorCorrupt | |||||
} | } | ||||
// Clean-up line from whitespace to pass it further (to base64 | |||||
// decoder). This is done after test for CRC and test for | |||||
// armorEnd. Keys that have whitespace in CRC will have CRC | |||||
// treated as part of the payload and probably fail in base64 | |||||
// reading. | |||||
line = bytes.Map(func(r rune) rune { | |||||
if ourIsSpace(r) { | |||||
return -1 | |||||
} | |||||
return r | |||||
}, line) | |||||
n = copy(p, line) | n = copy(p, line) | ||||
bytesToSave := len(line) - n | bytesToSave := len(line) - n | ||||
if bytesToSave > 0 { | if bytesToSave > 0 { |
return elliptic.Unmarshal(curve, data) | return elliptic.Unmarshal(curve, data) | ||||
} | } | ||||
func GenerateKey(curve elliptic.Curve, random io.Reader) (priv *PrivateKey, err error) { | |||||
var privBytes []byte | |||||
var Vx, Vy *big.Int | |||||
if _, ok := curve25519.ToCurve25519(curve); ok { | |||||
privBytes = make([]byte, 32) | |||||
_, err = io.ReadFull(random, privBytes) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
// NOTE: PGP expect scalars in reverse order than Curve 25519 | |||||
// go library. That's why this trimming is backwards compared | |||||
// to curve25519.go | |||||
privBytes[31] &= 248 | |||||
privBytes[0] &= 127 | |||||
privBytes[0] |= 64 | |||||
Vx,Vy = curve.ScalarBaseMult(privBytes) | |||||
} else { | |||||
privBytes, Vx, Vy, err = elliptic.GenerateKey(curve, random) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
} | |||||
priv = &PrivateKey{} | |||||
priv.X = new(big.Int).SetBytes(privBytes) | |||||
priv.PublicKey.Curve = curve | |||||
priv.PublicKey.X = Vx | |||||
priv.PublicKey.Y = Vy | |||||
return priv, nil | |||||
} |
func (upte UnknownPacketTypeError) Error() string { | func (upte UnknownPacketTypeError) Error() string { | ||||
return "openpgp: unknown packet type: " + strconv.Itoa(int(upte)) | return "openpgp: unknown packet type: " + strconv.Itoa(int(upte)) | ||||
} | } | ||||
// DeprecatedKeyError indicates that the key was read and verified | |||||
// properly, but uses a deprecated algorithm and can't be used. | |||||
type DeprecatedKeyError string | |||||
func (d DeprecatedKeyError) Error() string { | |||||
return "openpgp: key is deprecated: " + string(d) | |||||
} |
func (e *Entity) encryptionKey(now time.Time) (Key, bool) { | func (e *Entity) encryptionKey(now time.Time) (Key, bool) { | ||||
candidateSubkey := -1 | candidateSubkey := -1 | ||||
// Iterate the keys to find the newest key | |||||
// Iterate the keys to find the newest, non-revoked key that can | |||||
// encrypt. | |||||
var maxTime time.Time | var maxTime time.Time | ||||
for i, subkey := range e.Subkeys { | for i, subkey := range e.Subkeys { | ||||
func (e *Entity) signingKey(now time.Time) (Key, bool) { | func (e *Entity) signingKey(now time.Time) (Key, bool) { | ||||
candidateSubkey := -1 | candidateSubkey := -1 | ||||
// Iterate the keys to find the newest, non-revoked key that can | |||||
// sign. | |||||
var maxTime time.Time | |||||
for i, subkey := range e.Subkeys { | for i, subkey := range e.Subkeys { | ||||
if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) && | if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) && | ||||
subkey.PrivateKey.PrivateKey != nil && | subkey.PrivateKey.PrivateKey != nil && | ||||
subkey.PublicKey.PubKeyAlgo.CanSign() && | subkey.PublicKey.PubKeyAlgo.CanSign() && | ||||
!subkey.Sig.KeyExpired(now) && | |||||
subkey.Revocation == nil && | subkey.Revocation == nil && | ||||
!subkey.Sig.KeyExpired(now) { | |||||
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { | |||||
candidateSubkey = i | candidateSubkey = i | ||||
maxTime = subkey.Sig.CreationTime | |||||
break | break | ||||
} | } | ||||
} | } | ||||
// Only register an identity once we've gotten a valid self-signature. | // 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 | // 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 | // no valid self-signatures were found. That's OK as long as there are | ||||
// other identies that make sense. | |||||
// other identities that make sense. | |||||
// | // | ||||
// NOTE! We might later see a revocation for this very same UID, and it | // 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 | // won't be undone. We've preserved this feature from the original | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if subKey.Sig != nil { | |||||
if err := subKey.PublicKey.ErrorIfDeprecated(); err != nil { | |||||
// Key passed signature check but is deprecated. | |||||
subKey.Sig = nil | |||||
lastErr = err | |||||
} | |||||
} | |||||
if subKey.Sig != nil { | if subKey.Sig != nil { | ||||
e.Subkeys = append(e.Subkeys, subKey) | e.Subkeys = append(e.Subkeys, subKey) | ||||
} else { | } else { | ||||
} | } | ||||
isPrimaryId := true | isPrimaryId := true | ||||
e.Identities[uid.Id] = &Identity{ | e.Identities[uid.Id] = &Identity{ | ||||
Name: uid.Name, | |||||
Name: uid.Id, | |||||
UserId: uid, | UserId: uid, | ||||
SelfSignature: &packet.Signature{ | SelfSignature: &packet.Signature{ | ||||
CreationTime: currentTime, | CreationTime: currentTime, | ||||
}, | }, | ||||
} | } | ||||
// 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)} | |||||
} | |||||
// Likewise for DefaultCipher. | |||||
if config != nil && config.DefaultCipher != 0 { | |||||
e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)} | |||||
} | |||||
e.Subkeys = make([]Subkey, 1) | e.Subkeys = make([]Subkey, 1) | ||||
e.Subkeys[0] = Subkey{ | e.Subkeys[0] = Subkey{ | ||||
PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), | PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), | ||||
if err != nil { | if err != nil { | ||||
return | 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() { | if e.PrivateKey.PrivateKey != nil && !config.ReuseSignatures() { | ||||
// If not reusing existing signatures, sign subkey using private key | |||||
// (subkey binding), but also sign primary key using subkey (primary | |||||
// key binding) if subkey is used for signing. | |||||
if subkey.Sig.FlagSign { | |||||
err = subkey.Sig.CrossSignKey(e.PrimaryKey, subkey.PrivateKey, config) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
} | |||||
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | ||||
if err != nil { | if err != nil { | ||||
return | return |
// private key must have been decrypted first. | // private key must have been decrypted first. | ||||
// If config is nil, sensible defaults will be used. | // If config is nil, sensible defaults will be used. | ||||
func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { | func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { | ||||
if priv == nil || priv.PrivateKey == nil { | |||||
return errors.InvalidArgumentError("attempting to decrypt with nil PrivateKey") | |||||
} | |||||
var err error | var err error | ||||
var b []byte | var b []byte | ||||
// padding oracle attacks. | // padding oracle attacks. | ||||
switch priv.PubKeyAlgo { | switch priv.PubKeyAlgo { | ||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||
b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes) | |||||
k := priv.PrivateKey.(*rsa.PrivateKey) | |||||
b, err = rsa.DecryptPKCS1v15(config.Random(), k, padToKeySize(&k.PublicKey, e.encryptedMPI1.bytes)) | |||||
case PubKeyAlgoElGamal: | case PubKeyAlgoElGamal: | ||||
c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) | c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) | ||||
c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) | c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) |
"github.com/keybase/go-crypto/cast5" | "github.com/keybase/go-crypto/cast5" | ||||
"github.com/keybase/go-crypto/openpgp/errors" | "github.com/keybase/go-crypto/openpgp/errors" | ||||
"github.com/keybase/go-crypto/rsa" | |||||
) | ) | ||||
// readFull is the same as io.ReadFull except that reading zero bytes returns | // readFull is the same as io.ReadFull except that reading zero bytes returns | ||||
PubKeyAlgoElGamal PublicKeyAlgorithm = 16 | PubKeyAlgoElGamal PublicKeyAlgorithm = 16 | ||||
PubKeyAlgoDSA PublicKeyAlgorithm = 17 | PubKeyAlgoDSA PublicKeyAlgorithm = 17 | ||||
// RFC 6637, Section 5. | // RFC 6637, Section 5. | ||||
PubKeyAlgoECDH PublicKeyAlgorithm = 18 | |||||
PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | |||||
PubKeyAlgoECDH PublicKeyAlgorithm = 18 | |||||
PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | |||||
PubKeyAlgoBadElGamal PublicKeyAlgorithm = 20 // Reserved (deprecated, formerly ElGamal Encrypt or Sign) | |||||
// RFC -1 | // RFC -1 | ||||
PubKeyAlgoEdDSA PublicKeyAlgorithm = 22 | |||||
PubKeyAlgoEdDSA PublicKeyAlgorithm = 22 | |||||
) | ) | ||||
// CanEncrypt returns true if it's possible to encrypt a message to a public | // CanEncrypt returns true if it's possible to encrypt a message to a public | ||||
numBytes := (int(bitLength) + 7) / 8 | numBytes := (int(bitLength) + 7) / 8 | ||||
mpi = make([]byte, numBytes) | mpi = make([]byte, numBytes) | ||||
_, err = readFull(r, mpi) | _, err = readFull(r, mpi) | ||||
return | |||||
} | |||||
// mpiLength returns the length of the given *big.Int when serialized as an | |||||
// MPI. | |||||
func mpiLength(n *big.Int) (mpiLengthInBytes int) { | |||||
mpiLengthInBytes = 2 /* MPI length */ | |||||
mpiLengthInBytes += (n.BitLen() + 7) / 8 | |||||
// According to RFC 4880 3.2. we should check that the MPI has no leading | |||||
// zeroes (at least when not an encrypted MPI?), but this implementation | |||||
// does generate leading zeroes, so we keep accepting them. | |||||
return | return | ||||
} | } | ||||
// writeMPI serializes a big integer to w. | // writeMPI serializes a big integer to w. | ||||
func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { | func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { | ||||
// Note that we can produce leading zeroes, in violation of RFC 4880 3.2. | |||||
// Implementations seem to be tolerant of them, and stripping them would | |||||
// make it complex to guarantee matching re-serialization. | |||||
_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) | _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) | ||||
if err == nil { | if err == nil { | ||||
_, err = w.Write(mpiBytes) | _, err = w.Write(mpiBytes) | ||||
return writeMPI(w, uint16(i.BitLen()), i.Bytes()) | return writeMPI(w, uint16(i.BitLen()), i.Bytes()) | ||||
} | } | ||||
// padToKeySize left-pads a MPI with zeroes to match the length of the | |||||
// specified RSA public. | |||||
func padToKeySize(pub *rsa.PublicKey, b []byte) []byte { | |||||
k := (pub.N.BitLen() + 7) / 8 | |||||
if len(b) >= k { | |||||
return b | |||||
} | |||||
bb := make([]byte, k) | |||||
copy(bb[len(bb)-len(b):], b) | |||||
return bb | |||||
} | |||||
// CompressionAlgo Represents the different compression algorithms | // CompressionAlgo Represents the different compression algorithms | ||||
// supported by OpenPGP (except for BZIP2, which is not currently | // supported by OpenPGP (except for BZIP2, which is not currently | ||||
// supported). See Section 9.3 of RFC 4880. | // supported). See Section 9.3 of RFC 4880. |
seed parsedMPI | seed parsedMPI | ||||
} | } | ||||
func (e *EdDSAPrivateKey) Seed() []byte { | |||||
return e.seed.bytes | |||||
} | |||||
func (e *EdDSAPrivateKey) Sign(digest []byte) (R, S []byte, err error) { | func (e *EdDSAPrivateKey) Sign(digest []byte) (R, S []byte, err error) { | ||||
r := bytes.NewReader(e.seed.bytes) | r := bytes.NewReader(e.seed.bytes) | ||||
publicKey, privateKey, err := ed25519.GenerateKey(r) | publicKey, privateKey, err := ed25519.GenerateKey(r) | ||||
return pk | return pk | ||||
} | } | ||||
func NewECDHPrivateKey(currentTime time.Time, priv *ecdh.PrivateKey) *PrivateKey { | |||||
pk := new(PrivateKey) | |||||
pk.PublicKey = *NewECDHPublicKey(currentTime, &priv.PublicKey) | |||||
pk.PrivateKey = priv | |||||
return pk | |||||
} | |||||
func (pk *PrivateKey) parse(r io.Reader) (err error) { | func (pk *PrivateKey) parse(r io.Reader) (err error) { | ||||
err = (&pk.PublicKey).parse(r) | err = (&pk.PublicKey).parse(r) | ||||
if err != nil { | if err != nil { | ||||
return pk.parseECDHPrivateKey(data) | return pk.parseECDHPrivateKey(data) | ||||
case PubKeyAlgoEdDSA: | case PubKeyAlgoEdDSA: | ||||
return pk.parseEdDSAPrivateKey(data) | return pk.parseEdDSAPrivateKey(data) | ||||
case PubKeyAlgoBadElGamal: | |||||
return errors.UnsupportedError("parsing el-gamal sign-or-encrypt privatekeys is unsupported") | |||||
default: | |||||
return errors.UnsupportedError("cannot parse this private key type") | |||||
} | } | ||||
panic("impossible") | |||||
} | } | ||||
func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) { | func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) { |
"github.com/keybase/go-crypto/openpgp/ecdh" | "github.com/keybase/go-crypto/openpgp/ecdh" | ||||
"github.com/keybase/go-crypto/openpgp/elgamal" | "github.com/keybase/go-crypto/openpgp/elgamal" | ||||
"github.com/keybase/go-crypto/openpgp/errors" | "github.com/keybase/go-crypto/openpgp/errors" | ||||
"github.com/keybase/go-crypto/openpgp/s2k" | |||||
"github.com/keybase/go-crypto/rsa" | "github.com/keybase/go-crypto/rsa" | ||||
) | ) | ||||
var ( | var ( | ||||
// NIST curve P-224 | |||||
oidCurveP224 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x21} | |||||
// NIST curve P-256 | // NIST curve P-256 | ||||
oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07} | oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07} | ||||
// NIST curve P-384 | // NIST curve P-384 | ||||
func getCurveByOid(oid []byte) elliptic.Curve { | func getCurveByOid(oid []byte) elliptic.Curve { | ||||
switch { | switch { | ||||
case bytes.Equal(oid, oidCurveP224): | |||||
return elliptic.P224() | |||||
case bytes.Equal(oid, oidCurveP256): | case bytes.Equal(oid, oidCurveP256): | ||||
return elliptic.P256() | return elliptic.P256() | ||||
case bytes.Equal(oid, oidCurveP384): | case bytes.Equal(oid, oidCurveP384): | ||||
return pk | return pk | ||||
} | } | ||||
func getCurveOid(curve elliptic.Curve) (res []byte, err error) { | |||||
switch curve { | |||||
case elliptic.P224(): | |||||
res = oidCurveP224 | |||||
case elliptic.P256(): | |||||
res = oidCurveP256 | |||||
case elliptic.P384(): | |||||
res = oidCurveP384 | |||||
case elliptic.P521(): | |||||
res = oidCurveP521 | |||||
case brainpool.P256r1(): | |||||
res = oidCurveP256r1 | |||||
case brainpool.P384r1(): | |||||
res = oidCurveP384r1 | |||||
case brainpool.P512r1(): | |||||
res = oidCurveP512r1 | |||||
case curve25519.Cv25519(): | |||||
res = oidCurve25519 | |||||
default: | |||||
err = errors.UnsupportedError("unknown curve") | |||||
} | |||||
return | |||||
} | |||||
func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey { | func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey { | ||||
pk := &PublicKey{ | pk := &PublicKey{ | ||||
CreationTime: creationTime, | CreationTime: creationTime, | ||||
PublicKey: pub, | PublicKey: pub, | ||||
ec: new(ecdsaKey), | ec: new(ecdsaKey), | ||||
} | } | ||||
switch pub.Curve { | |||||
case elliptic.P256(): | |||||
pk.ec.oid = oidCurveP256 | |||||
case elliptic.P384(): | |||||
pk.ec.oid = oidCurveP384 | |||||
case elliptic.P521(): | |||||
pk.ec.oid = oidCurveP521 | |||||
case brainpool.P256r1(): | |||||
pk.ec.oid = oidCurveP256r1 | |||||
case brainpool.P384r1(): | |||||
pk.ec.oid = oidCurveP384r1 | |||||
case brainpool.P512r1(): | |||||
pk.ec.oid = oidCurveP512r1 | |||||
oid, _ := getCurveOid(pub.Curve) | |||||
pk.ec.oid = oid | |||||
bs, bitLen := ecdh.Marshal(pub.Curve, pub.X, pub.Y) | |||||
pk.ec.p.bytes = bs | |||||
pk.ec.p.bitLength = uint16(bitLen) | |||||
pk.setFingerPrintAndKeyId() | |||||
return pk | |||||
} | |||||
func NewECDHPublicKey(creationTime time.Time, pub *ecdh.PublicKey) *PublicKey { | |||||
pk := &PublicKey{ | |||||
CreationTime: creationTime, | |||||
PubKeyAlgo: PubKeyAlgoECDH, | |||||
PublicKey: pub, | |||||
ec: new(ecdsaKey), | |||||
} | |||||
oid, _ := getCurveOid(pub.Curve) | |||||
pk.ec.oid = oid | |||||
bs, bitLen := ecdh.Marshal(pub.Curve, pub.X, pub.Y) | |||||
pk.ec.p.bytes = bs | |||||
pk.ec.p.bitLength = uint16(bitLen) | |||||
hashbyte, _ := s2k.HashToHashId(crypto.SHA512) | |||||
pk.ecdh = &ecdhKdf{ | |||||
KdfHash: kdfHashFunction(hashbyte), | |||||
KdfAlgo: kdfAlgorithm(CipherAES256), | |||||
} | } | ||||
pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) | |||||
pk.ec.p.bitLength = uint16(8 * len(pk.ec.p.bytes)) | |||||
pk.setFingerPrintAndKeyId() | pk.setFingerPrintAndKeyId() | ||||
return pk | return pk | ||||
return err | return err | ||||
} | } | ||||
err = pk.edk.check() | err = pk.edk.check() | ||||
if err == nil { | |||||
pk.PublicKey = ed25519.PublicKey(pk.edk.p.bytes[1:]) | |||||
} | |||||
case PubKeyAlgoECDSA: | case PubKeyAlgoECDSA: | ||||
pk.ec = new(ecdsaKey) | pk.ec = new(ecdsaKey) | ||||
if err = pk.ec.parse(r); err != nil { | if err = pk.ec.parse(r); err != nil { | ||||
return | return | ||||
} | } | ||||
pk.PublicKey, err = pk.ec.newECDH() | pk.PublicKey, err = pk.ec.newECDH() | ||||
case PubKeyAlgoBadElGamal: | |||||
// Key has ElGamal format but nil-implementation - it will | |||||
// load but it's not possible to do any operations using this | |||||
// key. | |||||
err = pk.parseElGamal(r) | |||||
if err != nil { | |||||
pk.PublicKey = nil | |||||
} | |||||
default: | default: | ||||
err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) | err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) | ||||
} | } | ||||
N: new(big.Int).SetBytes(pk.n.bytes), | N: new(big.Int).SetBytes(pk.n.bytes), | ||||
E: 0, | E: 0, | ||||
} | } | ||||
// Warning: incompatibility with crypto/rsa: keybase fork uses | |||||
// int64 public exponents instead of int32. | |||||
for i := 0; i < len(pk.e.bytes); i++ { | for i := 0; i < len(pk.e.bytes); i++ { | ||||
rsa.E <<= 8 | rsa.E <<= 8 | ||||
rsa.E |= int64(pk.e.bytes[i]) | rsa.E |= int64(pk.e.bytes[i]) | ||||
pLength += 2 + uint16(len(pk.q.bytes)) | pLength += 2 + uint16(len(pk.q.bytes)) | ||||
pLength += 2 + uint16(len(pk.g.bytes)) | pLength += 2 + uint16(len(pk.g.bytes)) | ||||
pLength += 2 + uint16(len(pk.y.bytes)) | pLength += 2 + uint16(len(pk.y.bytes)) | ||||
case PubKeyAlgoElGamal: | |||||
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal: | |||||
pLength += 2 + uint16(len(pk.p.bytes)) | pLength += 2 + uint16(len(pk.p.bytes)) | ||||
pLength += 2 + uint16(len(pk.g.bytes)) | pLength += 2 + uint16(len(pk.g.bytes)) | ||||
pLength += 2 + uint16(len(pk.y.bytes)) | pLength += 2 + uint16(len(pk.y.bytes)) | ||||
length += 2 + len(pk.q.bytes) | length += 2 + len(pk.q.bytes) | ||||
length += 2 + len(pk.g.bytes) | length += 2 + len(pk.g.bytes) | ||||
length += 2 + len(pk.y.bytes) | length += 2 + len(pk.y.bytes) | ||||
case PubKeyAlgoElGamal: | |||||
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal: | |||||
length += 2 + len(pk.p.bytes) | length += 2 + len(pk.p.bytes) | ||||
length += 2 + len(pk.g.bytes) | length += 2 + len(pk.g.bytes) | ||||
length += 2 + len(pk.y.bytes) | length += 2 + len(pk.y.bytes) | ||||
return writeMPIs(w, pk.n, pk.e) | return writeMPIs(w, pk.n, pk.e) | ||||
case PubKeyAlgoDSA: | case PubKeyAlgoDSA: | ||||
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y) | return writeMPIs(w, pk.p, pk.q, pk.g, pk.y) | ||||
case PubKeyAlgoElGamal: | |||||
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal: | |||||
return writeMPIs(w, pk.p, pk.g, pk.y) | return writeMPIs(w, pk.p, pk.g, pk.y) | ||||
case PubKeyAlgoECDSA: | case PubKeyAlgoECDSA: | ||||
return pk.ec.serialize(w) | return pk.ec.serialize(w) | ||||
switch pk.PubKeyAlgo { | switch pk.PubKeyAlgo { | ||||
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) | rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) | ||||
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes) | |||||
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)) | |||||
if err != nil { | if err != nil { | ||||
return errors.SignatureError("RSA verification failure") | return errors.SignatureError("RSA verification failure") | ||||
} | } | ||||
switch pk.PubKeyAlgo { | switch pk.PubKeyAlgo { | ||||
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
rsaPublicKey := pk.PublicKey.(*rsa.PublicKey) | rsaPublicKey := pk.PublicKey.(*rsa.PublicKey) | ||||
if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { | |||||
if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil { | |||||
return errors.SignatureError("RSA verification failure") | return errors.SignatureError("RSA verification failure") | ||||
} | } | ||||
return | return | ||||
bitLength = pk.n.bitLength | bitLength = pk.n.bitLength | ||||
case PubKeyAlgoDSA: | case PubKeyAlgoDSA: | ||||
bitLength = pk.p.bitLength | bitLength = pk.p.bitLength | ||||
case PubKeyAlgoElGamal: | |||||
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal: | |||||
bitLength = pk.p.bitLength | bitLength = pk.p.bitLength | ||||
case PubKeyAlgoECDH: | case PubKeyAlgoECDH: | ||||
ecdhPublicKey := pk.PublicKey.(*ecdh.PublicKey) | ecdhPublicKey := pk.PublicKey.(*ecdh.PublicKey) | ||||
} | } | ||||
return | return | ||||
} | } | ||||
func (pk *PublicKey) ErrorIfDeprecated() error { | |||||
switch pk.PubKeyAlgo { | |||||
case PubKeyAlgoBadElGamal: | |||||
return errors.DeprecatedKeyError("ElGamal Encrypt or Sign (algo 20) is deprecated") | |||||
default: | |||||
return nil | |||||
} | |||||
} |
return | return | ||||
} | } | ||||
rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)} | rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)} | ||||
// Warning: incompatibility with crypto/rsa: keybase fork uses | |||||
// int64 public exponents instead of int32. | |||||
for i := 0; i < len(pk.e.bytes); i++ { | for i := 0; i < len(pk.e.bytes); i++ { | ||||
rsa.E <<= 8 | rsa.E <<= 8 | ||||
rsa.E |= int64(pk.e.bytes[i]) | rsa.E |= int64(pk.e.bytes[i]) |
"crypto/dsa" | "crypto/dsa" | ||||
"crypto/ecdsa" | "crypto/ecdsa" | ||||
"encoding/binary" | "encoding/binary" | ||||
"fmt" | |||||
"hash" | "hash" | ||||
"io" | "io" | ||||
"strconv" | "strconv" | ||||
err = errors.StructuralError("empty key flags subpacket") | err = errors.StructuralError("empty key flags subpacket") | ||||
return | return | ||||
} | } | ||||
sig.FlagsValid = true | |||||
if subpacket[0]&KeyFlagCertify != 0 { | |||||
sig.FlagCertify = true | |||||
} | |||||
if subpacket[0]&KeyFlagSign != 0 { | |||||
sig.FlagSign = true | |||||
} | |||||
if subpacket[0]&KeyFlagEncryptCommunications != 0 { | |||||
sig.FlagEncryptCommunications = true | |||||
} | |||||
if subpacket[0]&KeyFlagEncryptStorage != 0 { | |||||
sig.FlagEncryptStorage = true | |||||
if subpacket[0] != 0 { | |||||
sig.FlagsValid = true | |||||
if subpacket[0]&KeyFlagCertify != 0 { | |||||
sig.FlagCertify = true | |||||
} | |||||
if subpacket[0]&KeyFlagSign != 0 { | |||||
sig.FlagSign = true | |||||
} | |||||
if subpacket[0]&KeyFlagEncryptCommunications != 0 { | |||||
sig.FlagEncryptCommunications = true | |||||
} | |||||
if subpacket[0]&KeyFlagEncryptStorage != 0 { | |||||
sig.FlagEncryptStorage = true | |||||
} | |||||
} | } | ||||
case reasonForRevocationSubpacket: | case reasonForRevocationSubpacket: | ||||
// Reason For Revocation, section 5.2.3.23 | // Reason For Revocation, section 5.2.3.23 | ||||
return | return | ||||
} | } | ||||
// Parameter check, if this is wrong we will make a signature but | |||||
// not serialize it later. | |||||
if sig.PubKeyAlgo != priv.PubKeyAlgo { | |||||
err = errors.InvalidArgumentError("signature pub key algo does not match priv key") | |||||
return | |||||
} | |||||
switch priv.PubKeyAlgo { | switch priv.PubKeyAlgo { | ||||
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
sig.RSASignature.bytes, err = rsa.SignPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest) | sig.RSASignature.bytes, err = rsa.SignPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest) | ||||
digest = digest[:subgroupSize] | digest = digest[:subgroupSize] | ||||
} | } | ||||
r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) | r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) | ||||
if err == nil { | |||||
sig.DSASigR.bytes = r.Bytes() | |||||
sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) | |||||
sig.DSASigS.bytes = s.Bytes() | |||||
sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) | |||||
if err != nil { | |||||
return err | |||||
} | } | ||||
sig.DSASigR.bytes = r.Bytes() | |||||
sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) | |||||
sig.DSASigS.bytes = s.Bytes() | |||||
sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) | |||||
case PubKeyAlgoECDSA: | case PubKeyAlgoECDSA: | ||||
r, s, err := ecdsa.Sign(config.Random(), priv.PrivateKey.(*ecdsa.PrivateKey), digest) | r, s, err := ecdsa.Sign(config.Random(), priv.PrivateKey.(*ecdsa.PrivateKey), digest) | ||||
if err == nil { | |||||
sig.ECDSASigR = FromBig(r) | |||||
sig.ECDSASigS = FromBig(s) | |||||
if err != nil { | |||||
return err | |||||
} | } | ||||
sig.ECDSASigR = FromBig(r) | |||||
sig.ECDSASigS = FromBig(s) | |||||
case PubKeyAlgoEdDSA: | case PubKeyAlgoEdDSA: | ||||
r, s, err := priv.PrivateKey.(*EdDSAPrivateKey).Sign(digest) | r, s, err := priv.PrivateKey.(*EdDSAPrivateKey).Sign(digest) | ||||
if err == nil { | |||||
sig.EdDSASigR = FromBytes(r) | |||||
sig.EdDSASigS = FromBytes(s) | |||||
if err != nil { | |||||
return err | |||||
} | } | ||||
sig.EdDSASigR = FromBytes(r) | |||||
sig.EdDSASigS = FromBytes(s) | |||||
default: | default: | ||||
err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) | |||||
err = errors.UnsupportedError("public key algorithm for signing: " + strconv.Itoa(int(priv.PubKeyAlgo))) | |||||
} | } | ||||
return | return | ||||
return sig.Sign(s, nil, config) | return sig.Sign(s, nil, config) | ||||
} | } | ||||
// CrossSignKey creates PrimaryKeyBinding signature in sig.EmbeddedSignature by | |||||
// signing `primary` key's hash using `priv` subkey private key. Primary public | |||||
// key is the `signee` here. | |||||
func (sig *Signature) CrossSignKey(primary *PublicKey, priv *PrivateKey, config *Config) error { | |||||
if len(sig.outSubpackets) > 0 { | |||||
return fmt.Errorf("outSubpackets already exists, looks like CrossSignKey was called after Sign") | |||||
} | |||||
sig.EmbeddedSignature = &Signature{ | |||||
CreationTime: sig.CreationTime, | |||||
SigType: SigTypePrimaryKeyBinding, | |||||
PubKeyAlgo: priv.PubKeyAlgo, | |||||
Hash: sig.Hash, | |||||
} | |||||
h, err := keySignatureHash(primary, &priv.PublicKey, sig.Hash) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
return sig.EmbeddedSignature.Sign(h, priv, config) | |||||
} | |||||
// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been | // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been | ||||
// called first. | // called first. | ||||
func (sig *Signature) Serialize(w io.Writer) (err error) { | func (sig *Signature) Serialize(w io.Writer) (err error) { | ||||
subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) | subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) | ||||
} | } | ||||
if sig.EmbeddedSignature != nil { | |||||
buf := bytes.NewBuffer(nil) | |||||
if err := sig.EmbeddedSignature.Serialize(buf); err == nil { | |||||
byteContent := buf.Bytes()[2:] // skip 2-byte length header | |||||
subpackets = append(subpackets, outputSubpacket{false, embeddedSignatureSubpacket, true, byteContent}) | |||||
} | |||||
} | |||||
return | return | ||||
} | } | ||||
return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) | return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) | ||||
} | } | ||||
plaintextKey = plaintextKey[1:] | plaintextKey = plaintextKey[1:] | ||||
if l := len(plaintextKey); l == 0 || l%cipherFunc.blockSize() != 0 { | |||||
return nil, cipherFunc, errors.StructuralError("length of decrypted key not a multiple of block size") | |||||
if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() { | |||||
return nil, cipherFunc, errors.StructuralError("length of decrypted key (" + strconv.Itoa(l) + ") " + | |||||
"not equal to cipher keysize (" + strconv.Itoa(cipherKeySize) + ")") | |||||
} | } | ||||
return plaintextKey, cipherFunc, nil | return plaintextKey, cipherFunc, nil | ||||
} | } | ||||
Signature *packet.Signature // the signature packet itself, if v4 (default) | Signature *packet.Signature // the signature packet itself, if v4 (default) | ||||
SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature | SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature | ||||
// Does the Message include multiple signatures? Also called "nested signatures". | |||||
MultiSig bool | |||||
decrypted io.ReadCloser | decrypted io.ReadCloser | ||||
} | } | ||||
continue | continue | ||||
} | } | ||||
if !pk.key.PrivateKey.Encrypted { | if !pk.key.PrivateKey.Encrypted { | ||||
if pk.key.PrivateKey.PrivateKey == nil { | |||||
// Key is stubbed | |||||
continue | |||||
} | |||||
if len(pk.encryptedKey.Key) == 0 { | if len(pk.encryptedKey.Key) == 0 { | ||||
pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) | |||||
err := pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) | |||||
if err != nil { | |||||
continue | |||||
} | |||||
} | } | ||||
if len(pk.encryptedKey.Key) == 0 { | if len(pk.encryptedKey.Key) == 0 { | ||||
continue | continue | ||||
return nil, err | return nil, err | ||||
} | } | ||||
case *packet.OnePassSignature: | case *packet.OnePassSignature: | ||||
if !p.IsLast { | |||||
return nil, errors.UnsupportedError("nested signatures") | |||||
if md.IsSigned { | |||||
// If IsSigned is set, it means we have multiple | |||||
// OnePassSignature packets. | |||||
md.MultiSig = true | |||||
if md.SignedBy != nil { | |||||
// We've already found the signature we were looking | |||||
// for, made by key that we had in keyring and can | |||||
// check signature against. Continue with that instead | |||||
// of trying to find another. | |||||
continue FindLiteralData | |||||
} | |||||
} | } | ||||
h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) | h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) | ||||
n, err = scr.md.LiteralData.Body.Read(buf) | n, err = scr.md.LiteralData.Body.Read(buf) | ||||
scr.wrappedHash.Write(buf[:n]) | scr.wrappedHash.Write(buf[:n]) | ||||
if err == io.EOF { | if err == io.EOF { | ||||
var p packet.Packet | |||||
p, scr.md.SignatureError = scr.packets.Next() | |||||
if scr.md.SignatureError != nil { | |||||
return | |||||
} | |||||
var ok bool | |||||
if scr.md.Signature, ok = p.(*packet.Signature); ok { | |||||
var err error | |||||
if fingerprint := scr.md.Signature.IssuerFingerprint; fingerprint != nil { | |||||
if !hmac.Equal(fingerprint, scr.md.SignedBy.PublicKey.Fingerprint[:]) { | |||||
err = errors.StructuralError("bad key fingerprint") | |||||
for { | |||||
var p packet.Packet | |||||
p, scr.md.SignatureError = scr.packets.Next() | |||||
if scr.md.SignatureError != nil { | |||||
if scr.md.MultiSig { | |||||
// If we are in MultiSig, we might have found other | |||||
// signature that cannot be verified using our key. | |||||
// Clear Signature field so it's clear for consumers | |||||
// that this message failed to verify. | |||||
scr.md.Signature = nil | |||||
} | } | ||||
return | |||||
} | } | ||||
if err == nil { | |||||
err = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | |||||
var ok bool | |||||
if scr.md.Signature, ok = p.(*packet.Signature); ok { | |||||
var err error | |||||
if keyID := scr.md.Signature.IssuerKeyId; keyID != nil { | |||||
if *keyID != scr.md.SignedBy.PublicKey.KeyId { | |||||
if scr.md.MultiSig { | |||||
continue // try again to find a sig we can verify | |||||
} | |||||
err = errors.StructuralError("bad key id") | |||||
} | |||||
} | |||||
if fingerprint := scr.md.Signature.IssuerFingerprint; fingerprint != nil { | |||||
if !hmac.Equal(fingerprint, scr.md.SignedBy.PublicKey.Fingerprint[:]) { | |||||
if scr.md.MultiSig { | |||||
continue // try again to find a sig we can verify | |||||
} | |||||
err = errors.StructuralError("bad key fingerprint") | |||||
} | |||||
} | |||||
if err == nil { | |||||
err = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | |||||
} | |||||
scr.md.SignatureError = err | |||||
} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { | |||||
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) | |||||
} else { | |||||
scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") | |||||
return | |||||
} | } | ||||
scr.md.SignatureError = err | |||||
} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { | |||||
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) | |||||
} else { | |||||
scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") | |||||
return | |||||
// Parse only one packet by default, unless message is MultiSig. Then | |||||
// we ask for more packets after discovering non-matching signature, | |||||
// until we find one that we can verify. | |||||
break | |||||
} | } | ||||
// The SymmetricallyEncrypted packet, if any, might have an | // The SymmetricallyEncrypted packet, if any, might have an |
return | return | ||||
} | } | ||||
hasher := crypto.SHA512 | |||||
if algo := config.Compression(); algo != packet.CompressionNone { | |||||
var compConfig *packet.CompressionConfig | |||||
if config != nil { | |||||
compConfig = config.CompressionConfig | |||||
} | |||||
out, err = packet.SerializeCompressed(out, algo, compConfig) | |||||
if err != nil { | |||||
return | |||||
} | |||||
} | |||||
hasher := config.Hash() // defaults to SHA-256 | |||||
ops := &packet.OnePassSignature{ | ops := &packet.OnePassSignature{ | ||||
SigType: packet.SigTypeBinary, | SigType: packet.SigTypeBinary, |
github.com/kballard/go-shellquote | github.com/kballard/go-shellquote | ||||
# github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd | # github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd | ||||
github.com/kevinburke/ssh_config | github.com/kevinburke/ssh_config | ||||
# github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6 | |||||
# github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 | |||||
github.com/keybase/go-crypto/brainpool | github.com/keybase/go-crypto/brainpool | ||||
github.com/keybase/go-crypto/cast5 | github.com/keybase/go-crypto/cast5 | ||||
github.com/keybase/go-crypto/curve25519 | github.com/keybase/go-crypto/curve25519 |