forked from gitea/gitea
update vendor keybase/go-crypto (#10234)
This commit is contained in:
parent
86fdba177a
commit
bfd62b6f01
2
go.mod
2
go.mod
|
@ -58,7 +58,7 @@ require (
|
||||||
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
|
||||||
|
|
7
go.sum
7
go.sum
|
@ -9,8 +9,6 @@ cloud.google.com/go v0.45.0 h1:bALuGBSgE+BD4rxsopAYlqjcwqcQtye6pWG4bC3N/k0=
|
||||||
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=
|
||||||
|
@ -340,8 +338,8 @@ github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 h1:vE7J1m7c
|
||||||
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-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+4tLukHoB9iqHOu3LmLhRmgUxZo6Vp4=
|
||||||
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/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=
|
||||||
|
@ -508,7 +506,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
||||||
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=
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// 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"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
// 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
|
|
@ -3,12 +3,12 @@
|
||||||
// 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
|
// These constants cannot be encoded in non-MOVQ immediates.
|
||||||
GLOBL ·REDMASK51(SB), 8, $8
|
// 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
|
||||||
|
|
|
@ -2,87 +2,64 @@
|
||||||
// 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
|
SUBQ $1, SI
|
||||||
MOVQ 0(DI),SI
|
NOTQ SI
|
||||||
MOVQ 80(DI),DX
|
MOVQ SI, X15
|
||||||
MOVQ 8(DI),CX
|
PSHUFD $0x44, X15, X15
|
||||||
MOVQ 88(DI),R8
|
|
||||||
MOVQ SI,R9
|
MOVOU 0(DI), X0
|
||||||
CMOVQEQ DX,SI
|
MOVOU 16(DI), X2
|
||||||
CMOVQEQ R9,DX
|
MOVOU 32(DI), X4
|
||||||
MOVQ CX,R9
|
MOVOU 48(DI), X6
|
||||||
CMOVQEQ R8,CX
|
MOVOU 64(DI), X8
|
||||||
CMOVQEQ R9,R8
|
MOVOU 80(DI), X1
|
||||||
MOVQ SI,0(DI)
|
MOVOU 96(DI), X3
|
||||||
MOVQ DX,80(DI)
|
MOVOU 112(DI), X5
|
||||||
MOVQ CX,8(DI)
|
MOVOU 128(DI), X7
|
||||||
MOVQ R8,88(DI)
|
MOVOU 144(DI), X9
|
||||||
MOVQ 16(DI),SI
|
|
||||||
MOVQ 96(DI),DX
|
MOVO X1, X10
|
||||||
MOVQ 24(DI),CX
|
MOVO X3, X11
|
||||||
MOVQ 104(DI),R8
|
MOVO X5, X12
|
||||||
MOVQ SI,R9
|
MOVO X7, X13
|
||||||
CMOVQEQ DX,SI
|
MOVO X9, X14
|
||||||
CMOVQEQ R9,DX
|
|
||||||
MOVQ CX,R9
|
PXOR X0, X10
|
||||||
CMOVQEQ R8,CX
|
PXOR X2, X11
|
||||||
CMOVQEQ R9,R8
|
PXOR X4, X12
|
||||||
MOVQ SI,16(DI)
|
PXOR X6, X13
|
||||||
MOVQ DX,96(DI)
|
PXOR X8, X14
|
||||||
MOVQ CX,24(DI)
|
PAND X15, X10
|
||||||
MOVQ R8,104(DI)
|
PAND X15, X11
|
||||||
MOVQ 32(DI),SI
|
PAND X15, X12
|
||||||
MOVQ 112(DI),DX
|
PAND X15, X13
|
||||||
MOVQ 40(DI),CX
|
PAND X15, X14
|
||||||
MOVQ 120(DI),R8
|
PXOR X10, X0
|
||||||
MOVQ SI,R9
|
PXOR X10, X1
|
||||||
CMOVQEQ DX,SI
|
PXOR X11, X2
|
||||||
CMOVQEQ R9,DX
|
PXOR X11, X3
|
||||||
MOVQ CX,R9
|
PXOR X12, X4
|
||||||
CMOVQEQ R8,CX
|
PXOR X12, X5
|
||||||
CMOVQEQ R9,R8
|
PXOR X13, X6
|
||||||
MOVQ SI,32(DI)
|
PXOR X13, X7
|
||||||
MOVQ DX,112(DI)
|
PXOR X14, X8
|
||||||
MOVQ CX,40(DI)
|
PXOR X14, X9
|
||||||
MOVQ R8,120(DI)
|
|
||||||
MOVQ 48(DI),SI
|
MOVOU X0, 0(DI)
|
||||||
MOVQ 128(DI),DX
|
MOVOU X2, 16(DI)
|
||||||
MOVQ 56(DI),CX
|
MOVOU X4, 32(DI)
|
||||||
MOVQ 136(DI),R8
|
MOVOU X6, 48(DI)
|
||||||
MOVQ SI,R9
|
MOVOU X8, 64(DI)
|
||||||
CMOVQEQ DX,SI
|
MOVOU X1, 80(DI)
|
||||||
CMOVQEQ R9,DX
|
MOVOU X3, 96(DI)
|
||||||
MOVQ CX,R9
|
MOVOU X5, 112(DI)
|
||||||
CMOVQEQ R8,CX
|
MOVOU X7, 128(DI)
|
||||||
CMOVQEQ R9,R8
|
MOVOU X9, 144(DI)
|
||||||
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
|
RET
|
||||||
|
|
|
@ -2,12 +2,16 @@
|
||||||
// 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.
|
||||||
|
|
||||||
|
@ -50,17 +54,11 @@ func feCopy(dst, src *fieldElement) {
|
||||||
//
|
//
|
||||||
// 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]
|
t := b & (f[i] ^ g[i])
|
||||||
}
|
f[i] ^= t
|
||||||
for i := range g {
|
g[i] ^= t
|
||||||
g[i] ^= x[i]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +73,7 @@ func load3(in []byte) int64 {
|
||||||
|
|
||||||
// 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
|
return int64(binary.LittleEndian.Uint32(in))
|
||||||
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) {
|
func feFromBytes(dst *fieldElement, src *[32]byte) {
|
||||||
|
|
|
@ -16,19 +16,30 @@ func copyReverse(dst []byte, src []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])
|
copyTruncate(x1Bytes[:], x1.Bytes())
|
||||||
copyReverse(scalarBytes[:], scalar[:32])
|
copyReverse(scalarBytes[:], scalar)
|
||||||
|
|
||||||
scalarMult(&dst, &scalarBytes, &x1Bytes)
|
scalarMult(&dst, &scalarBytes, &x1Bytes)
|
||||||
|
|
||||||
|
@ -63,7 +74,7 @@ func (cv25519Curve) MarshalType40(x, y *big.Int) []byte {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +102,10 @@ func initCv25519() {
|
||||||
// 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.P, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16)
|
||||||
cv25519.N, _ = new (big.Int).SetString("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16)
|
cv25519.N, _ = new(big.Int).SetString("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16)
|
||||||
cv25519.Gx, _ = new (big.Int).SetString("9", 16)
|
cv25519.Gx, _ = new(big.Int).SetString("9", 16)
|
||||||
cv25519.Gy, _ = new (big.Int).SetString("20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9", 16)
|
cv25519.Gy, _ = new(big.Int).SetString("20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9", 16)
|
||||||
cv25519.BitSize = 256
|
cv25519.BitSize = 256
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
// 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
|
// the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html
|
||||||
package curve25519
|
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}
|
||||||
|
|
|
@ -3,33 +3,22 @@
|
||||||
// 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
|
||||||
|
@ -81,14 +70,4 @@ REDUCELOOP:
|
||||||
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
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,40 +3,28 @@
|
||||||
// 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
|
||||||
|
@ -111,11 +99,11 @@ TEXT ·mul(SB),0,$128-24
|
||||||
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
|
||||||
|
@ -123,19 +111,19 @@ TEXT ·mul(SB),0,$128-24
|
||||||
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
|
||||||
|
@ -178,14 +166,4 @@ TEXT ·mul(SB),0,$128-24
|
||||||
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
|
||||||
|
|
|
@ -3,28 +3,17 @@
|
||||||
// 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
|
||||||
|
@ -97,7 +86,7 @@ TEXT ·square(SB),7,$96-16
|
||||||
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
|
||||||
|
@ -140,14 +129,4 @@ TEXT ·square(SB),7,$96-16
|
||||||
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
|
||||||
|
|
|
@ -3,20 +3,23 @@
|
||||||
// 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"
|
||||||
|
@ -31,6 +34,8 @@ const (
|
||||||
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.
|
||||||
|
@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.PublicKey {
|
||||||
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
|
||||||
|
@ -61,19 +75,33 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
|
||||||
|
|
||||||
// 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)
|
seed := make([]byte, SeedSize)
|
||||||
publicKey = make([]byte, PublicKeySize)
|
if _, err := io.ReadFull(rand, seed); err != nil {
|
||||||
_, err = io.ReadFull(rand, privateKey[:32])
|
|
||||||
if 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
|
||||||
|
@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er
|
||||||
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
|
||||||
|
@ -171,11 +200,18 @@ func Verify(publicKey PublicKey, message, sig []byte) bool {
|
||||||
edwards25519.ScReduce(&hReduced, &digest)
|
edwards25519.ScReduce(&hReduced, &digest)
|
||||||
|
|
||||||
var R edwards25519.ProjectiveGroupElement
|
var R edwards25519.ProjectiveGroupElement
|
||||||
var b [32]byte
|
var s [32]byte
|
||||||
copy(b[:], sig[32:])
|
copy(s[:], sig[32:])
|
||||||
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)
|
|
||||||
|
// 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[:])
|
||||||
}
|
}
|
||||||
|
|
22
vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
22
vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
@ -1769,3 +1771,23 @@ func ScReduce(out *[32]byte, s *[64]byte) {
|
||||||
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
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
@ -89,50 +90,114 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
|
||||||
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] == '=' {
|
lineWithChecksum := false
|
||||||
// This is the checksum line
|
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:])
|
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[len(line)-4:])
|
||||||
if m != 3 || err != nil {
|
if err != nil {
|
||||||
return
|
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) {
|
expectArmorEnd = true
|
||||||
return 0, ArmorCorrupt
|
|
||||||
}
|
|
||||||
|
|
||||||
l.eof = true
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
|
|
@ -280,3 +280,37 @@ func Unmarshal(curve elliptic.Curve, data []byte) (x, y *big.Int) {
|
||||||
|
|
||||||
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
|
||||||
|
}
|
||||||
|
|
|
@ -70,3 +70,11 @@ type UnknownPacketTypeError uint8
|
||||||
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)
|
||||||
|
}
|
||||||
|
|
|
@ -118,7 +118,8 @@ func (e *Entity) primaryIdentity() *Identity {
|
||||||
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 {
|
||||||
|
|
||||||
|
@ -172,13 +173,18 @@ func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,7 +510,7 @@ EachPacket:
|
||||||
// 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
|
||||||
|
@ -645,6 +651,15 @@ func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
@ -690,7 +705,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
||||||
}
|
}
|
||||||
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,
|
||||||
|
@ -705,6 +720,17 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
@ -756,10 +782,16 @@ func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error
|
||||||
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
|
||||||
|
|
|
@ -83,6 +83,10 @@ func checksumKeyMaterial(key []byte) uint16 {
|
||||||
// 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
|
||||||
|
|
||||||
|
@ -90,7 +94,8 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
|
||||||
// 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)
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
|
|
||||||
"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
|
||||||
|
@ -413,10 +414,12 @@ const (
|
||||||
PubKeyAlgoElGamal PublicKeyAlgorithm = 16
|
PubKeyAlgoElGamal PublicKeyAlgorithm = 16
|
||||||
PubKeyAlgoDSA PublicKeyAlgorithm = 17
|
PubKeyAlgoDSA PublicKeyAlgorithm = 17
|
||||||
// RFC 6637, Section 5.
|
// RFC 6637, Section 5.
|
||||||
PubKeyAlgoECDH PublicKeyAlgorithm = 18
|
PubKeyAlgoECDH PublicKeyAlgorithm = 18
|
||||||
PubKeyAlgoECDSA PublicKeyAlgorithm = 19
|
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
|
||||||
|
@ -507,19 +510,17 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) {
|
||||||
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
|
// 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.
|
||||||
// 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
|
|
||||||
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)
|
||||||
|
@ -551,6 +552,18 @@ func writeBig(w io.Writer, i *big.Int) error {
|
||||||
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.
|
||||||
|
|
|
@ -44,6 +44,10 @@ type EdDSAPrivateKey struct {
|
||||||
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)
|
||||||
|
@ -89,6 +93,13 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK
|
||||||
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 {
|
||||||
|
@ -415,8 +426,11 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) {
|
||||||
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) {
|
||||||
|
|
|
@ -27,10 +27,13 @@ import (
|
||||||
"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
|
||||||
|
@ -128,6 +131,8 @@ func (f *ecdsaKey) serialize(w io.Writer) (err error) {
|
||||||
|
|
||||||
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):
|
||||||
|
@ -324,6 +329,30 @@ func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *Public
|
||||||
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,
|
||||||
|
@ -331,22 +360,34 @@ func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey
|
||||||
PublicKey: pub,
|
PublicKey: pub,
|
||||||
ec: new(ecdsaKey),
|
ec: new(ecdsaKey),
|
||||||
}
|
}
|
||||||
switch pub.Curve {
|
oid, _ := getCurveOid(pub.Curve)
|
||||||
case elliptic.P256():
|
pk.ec.oid = oid
|
||||||
pk.ec.oid = oidCurveP256
|
bs, bitLen := ecdh.Marshal(pub.Curve, pub.X, pub.Y)
|
||||||
case elliptic.P384():
|
pk.ec.p.bytes = bs
|
||||||
pk.ec.oid = oidCurveP384
|
pk.ec.p.bitLength = uint16(bitLen)
|
||||||
case elliptic.P521():
|
|
||||||
pk.ec.oid = oidCurveP521
|
pk.setFingerPrintAndKeyId()
|
||||||
case brainpool.P256r1():
|
return pk
|
||||||
pk.ec.oid = oidCurveP256r1
|
}
|
||||||
case brainpool.P384r1():
|
|
||||||
pk.ec.oid = oidCurveP384r1
|
func NewECDHPublicKey(creationTime time.Time, pub *ecdh.PublicKey) *PublicKey {
|
||||||
case brainpool.P512r1():
|
pk := &PublicKey{
|
||||||
pk.ec.oid = oidCurveP512r1
|
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
|
||||||
|
@ -377,6 +418,9 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
|
||||||
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 {
|
||||||
|
@ -393,6 +437,14 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
|
||||||
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)))
|
||||||
}
|
}
|
||||||
|
@ -433,6 +485,8 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
|
||||||
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])
|
||||||
|
@ -508,7 +562,7 @@ func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) {
|
||||||
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))
|
||||||
|
@ -539,7 +593,7 @@ func (pk *PublicKey) Serialize(w io.Writer) (err error) {
|
||||||
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)
|
||||||
|
@ -587,7 +641,7 @@ func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
|
||||||
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)
|
||||||
|
@ -637,7 +691,7 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
@ -694,7 +748,7 @@ func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err
|
||||||
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
|
||||||
|
@ -910,7 +964,7 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
|
||||||
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)
|
||||||
|
@ -928,3 +982,12 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
|
||||||
}
|
}
|
||||||
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -105,6 +105,8 @@ func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) {
|
||||||
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])
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -384,18 +385,20 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
|
||||||
err = errors.StructuralError("empty key flags subpacket")
|
err = errors.StructuralError("empty key flags subpacket")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sig.FlagsValid = true
|
if subpacket[0] != 0 {
|
||||||
if subpacket[0]&KeyFlagCertify != 0 {
|
sig.FlagsValid = true
|
||||||
sig.FlagCertify = true
|
if subpacket[0]&KeyFlagCertify != 0 {
|
||||||
}
|
sig.FlagCertify = true
|
||||||
if subpacket[0]&KeyFlagSign != 0 {
|
}
|
||||||
sig.FlagSign = true
|
if subpacket[0]&KeyFlagSign != 0 {
|
||||||
}
|
sig.FlagSign = true
|
||||||
if subpacket[0]&KeyFlagEncryptCommunications != 0 {
|
}
|
||||||
sig.FlagEncryptCommunications = true
|
if subpacket[0]&KeyFlagEncryptCommunications != 0 {
|
||||||
}
|
sig.FlagEncryptCommunications = true
|
||||||
if subpacket[0]&KeyFlagEncryptStorage != 0 {
|
}
|
||||||
sig.FlagEncryptStorage = 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
|
||||||
|
@ -624,6 +627,13 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
|
||||||
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)
|
||||||
|
@ -637,26 +647,29 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
|
||||||
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 {
|
if err != nil {
|
||||||
sig.DSASigR.bytes = r.Bytes()
|
return err
|
||||||
sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
|
|
||||||
sig.DSASigS.bytes = s.Bytes()
|
|
||||||
sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
|
|
||||||
}
|
}
|
||||||
|
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 {
|
if err != nil {
|
||||||
sig.ECDSASigR = FromBig(r)
|
return err
|
||||||
sig.ECDSASigS = FromBig(s)
|
|
||||||
}
|
}
|
||||||
|
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 {
|
if err != nil {
|
||||||
sig.EdDSASigR = FromBytes(r)
|
return err
|
||||||
sig.EdDSASigS = FromBytes(s)
|
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
@ -704,6 +717,28 @@ func (sig *Signature) SignKeyWithSigner(signeePubKey *PublicKey, signerPubKey *P
|
||||||
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) {
|
||||||
|
@ -832,6 +867,14 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,10 +91,10 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunc
|
||||||
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 {
|
if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() {
|
||||||
return nil, cipherFunc, errors.StructuralError("length of decrypted key not a multiple of block size")
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,9 @@ type MessageDetails struct {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,8 +161,15 @@ FindKey:
|
||||||
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
|
||||||
|
@ -244,8 +254,17 @@ FindLiteralData:
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case *packet.OnePassSignature:
|
case *packet.OnePassSignature:
|
||||||
if !p.IsLast {
|
if md.IsSigned {
|
||||||
return nil, errors.UnsupportedError("nested signatures")
|
// 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)
|
||||||
|
@ -329,29 +348,54 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
|
||||||
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
|
for {
|
||||||
p, scr.md.SignatureError = scr.packets.Next()
|
var p packet.Packet
|
||||||
if scr.md.SignatureError != nil {
|
p, scr.md.SignatureError = scr.packets.Next()
|
||||||
return
|
if scr.md.SignatureError != nil {
|
||||||
}
|
if scr.md.MultiSig {
|
||||||
|
// If we are in MultiSig, we might have found other
|
||||||
var ok bool
|
// signature that cannot be verified using our key.
|
||||||
if scr.md.Signature, ok = p.(*packet.Signature); ok {
|
// Clear Signature field so it's clear for consumers
|
||||||
var err error
|
// that this message failed to verify.
|
||||||
if fingerprint := scr.md.Signature.IssuerFingerprint; fingerprint != nil {
|
scr.md.Signature = nil
|
||||||
if !hmac.Equal(fingerprint, scr.md.SignedBy.PublicKey.Fingerprint[:]) {
|
|
||||||
err = errors.StructuralError("bad key fingerprint")
|
|
||||||
}
|
}
|
||||||
|
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 {
|
// Parse only one packet by default, unless message is MultiSig. Then
|
||||||
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3)
|
// we ask for more packets after discovering non-matching signature,
|
||||||
} else {
|
// until we find one that we can verify.
|
||||||
scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature")
|
break
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The SymmetricallyEncrypted packet, if any, might have an
|
// The SymmetricallyEncrypted packet, if any, might have an
|
||||||
|
|
|
@ -458,7 +458,18 @@ func AttachedSign(out io.WriteCloser, signed Entity, hints *FileHints,
|
||||||
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,
|
||||||
|
|
|
@ -253,7 +253,7 @@ github.com/jessevdk/go-flags
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue