update vendor keybase/go-crypto (#10234)

This commit is contained in:
6543 2020-02-11 19:58:23 +01:00 committed by GitHub
parent 86fdba177a
commit bfd62b6f01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1062 additions and 769 deletions

2
go.mod
View file

@ -58,7 +58,7 @@ require (
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/joho/godotenv v1.3.0 // indirect
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/lafriks/xormstore v1.3.2
github.com/lib/pq v1.2.0

7
go.sum
View file

@ -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/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=
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/go.mod h1:G7hVb908t0Bl0uk7zGSg14fyzNtxgtD9Shf04wkMK7s=
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/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/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/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
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/go.mod h1:qQeCMRwzMF3ckeGr+h0tJLdxXnq+NVZsIDMELj0t028=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=

View file

@ -4,7 +4,7 @@
// Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common
// OpenPGP cipher.
package cast5
package cast5 // import "github.com/keybase/go-crypto/cast5"
import "errors"

View file

@ -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

View file

@ -3,12 +3,12 @@
// 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
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +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
GLOBL ·_121666_213(SB), 8, $8

View file

@ -2,87 +2,64 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine
// func cswap(inout *[5]uint64, v uint64)
// func cswap(inout *[4][5]uint64, v uint64)
TEXT ·cswap(SB),7,$0
MOVQ inout+0(FP),DI
MOVQ v+8(FP),SI
CMPQ SI,$1
MOVQ 0(DI),SI
MOVQ 80(DI),DX
MOVQ 8(DI),CX
MOVQ 88(DI),R8
MOVQ SI,R9
CMOVQEQ DX,SI
CMOVQEQ R9,DX
MOVQ CX,R9
CMOVQEQ R8,CX
CMOVQEQ R9,R8
MOVQ SI,0(DI)
MOVQ DX,80(DI)
MOVQ CX,8(DI)
MOVQ R8,88(DI)
MOVQ 16(DI),SI
MOVQ 96(DI),DX
MOVQ 24(DI),CX
MOVQ 104(DI),R8
MOVQ SI,R9
CMOVQEQ DX,SI
CMOVQEQ R9,DX
MOVQ CX,R9
CMOVQEQ R8,CX
CMOVQEQ R9,R8
MOVQ SI,16(DI)
MOVQ DX,96(DI)
MOVQ CX,24(DI)
MOVQ R8,104(DI)
MOVQ 32(DI),SI
MOVQ 112(DI),DX
MOVQ 40(DI),CX
MOVQ 120(DI),R8
MOVQ SI,R9
CMOVQEQ DX,SI
CMOVQEQ R9,DX
MOVQ CX,R9
CMOVQEQ R8,CX
CMOVQEQ R9,R8
MOVQ SI,32(DI)
MOVQ DX,112(DI)
MOVQ CX,40(DI)
MOVQ R8,120(DI)
MOVQ 48(DI),SI
MOVQ 128(DI),DX
MOVQ 56(DI),CX
MOVQ 136(DI),R8
MOVQ SI,R9
CMOVQEQ DX,SI
CMOVQEQ R9,DX
MOVQ CX,R9
CMOVQEQ R8,CX
CMOVQEQ R9,R8
MOVQ SI,48(DI)
MOVQ DX,128(DI)
MOVQ CX,56(DI)
MOVQ R8,136(DI)
MOVQ 64(DI),SI
MOVQ 144(DI),DX
MOVQ 72(DI),CX
MOVQ 152(DI),R8
MOVQ SI,R9
CMOVQEQ DX,SI
CMOVQEQ R9,DX
MOVQ CX,R9
CMOVQEQ R8,CX
CMOVQEQ R9,R8
MOVQ SI,64(DI)
MOVQ DX,144(DI)
MOVQ CX,72(DI)
MOVQ R8,152(DI)
MOVQ DI,AX
MOVQ SI,DX
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

View file

@ -2,12 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// We have a implementation in amd64 assembly so this code is only run on
// We have an implementation in amd64 assembly so this code is only run on
// non-amd64 platforms. The amd64 assembly does not support gccgo.
// +build !amd64 gccgo appengine
package curve25519
import (
"encoding/binary"
)
// This code is a port of the public domain, "ref10" implementation of
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
@ -50,17 +54,11 @@ func feCopy(dst, src *fieldElement) {
//
// Preconditions: b in {0,1}.
func feCSwap(f, g *fieldElement, b int32) {
var x fieldElement
b = -b
for i := range x {
x[i] = b & (f[i] ^ g[i])
}
for i := range f {
f[i] ^= x[i]
}
for i := range g {
g[i] ^= x[i]
t := b & (f[i] ^ g[i])
f[i] ^= t
g[i] ^= t
}
}
@ -75,12 +73,7 @@ func load3(in []byte) int64 {
// load4 reads a 32-bit, little-endian value from in.
func load4(in []byte) int64 {
var r int64
r = int64(in[0])
r |= int64(in[1]) << 8
r |= int64(in[2]) << 16
r |= int64(in[3]) << 24
return r
return int64(binary.LittleEndian.Uint32(in))
}
func feFromBytes(dst *fieldElement, src *[32]byte) {

View file

@ -16,19 +16,30 @@ func copyReverse(dst []byte, src []byte) {
// Curve 25519 multiplication functions expect scalars in reverse
// order than PGP. To keep the curve25519Curve type consistent
// with other curves, we reverse it here.
for i, j := 0, len(src)-1; j >= 0; i, j = i+1, j-1 {
for i, j := 0, len(src)-1; j >= 0 && i < len(dst); i, j = i+1, j-1 {
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) {
// Assume y1 is 0 with cv25519.
var dst [32]byte
var x1Bytes [32]byte
var scalarBytes [32]byte
copy(x1Bytes[:], x1.Bytes()[:32])
copyReverse(scalarBytes[:], scalar[:32])
copyTruncate(x1Bytes[:], x1.Bytes())
copyReverse(scalarBytes[:], scalar)
scalarMult(&dst, &scalarBytes, &x1Bytes)
@ -63,7 +74,7 @@ func (cv25519Curve) MarshalType40(x, y *big.Int) []byte {
ret[0] = 0x40
xBytes := x.Bytes()
copy(ret[1+byteLen-len(xBytes):], xBytes)
copyTruncate(ret[1:], xBytes)
return ret
}

View file

@ -3,8 +3,8 @@
// license that can be found in the LICENSE file.
// Package curve25519 provides an implementation of scalar multiplication on
// the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html
package curve25519
// 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.
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}

View file

@ -3,33 +3,22 @@
// 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
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func freeze(inout *[5]uint64)
TEXT ·freeze(SB),7,$96-8
TEXT ·freeze(SB),7,$0-8
MOVQ inout+0(FP), DI
MOVQ SP,R11
MOVQ $31,CX
NOTQ CX
ANDQ CX,SP
ADDQ $32,SP
MOVQ R11,0(SP)
MOVQ R12,8(SP)
MOVQ R13,16(SP)
MOVQ R14,24(SP)
MOVQ R15,32(SP)
MOVQ BX,40(SP)
MOVQ BP,48(SP)
MOVQ 0(DI),SI
MOVQ 8(DI),DX
MOVQ 16(DI),CX
MOVQ 24(DI),R8
MOVQ 32(DI),R9
MOVQ ·REDMASK51(SB),AX
MOVQ $REDMASK51,AX
MOVQ AX,R10
SUBQ $18,R10
MOVQ $3,R11
@ -81,14 +70,4 @@ REDUCELOOP:
MOVQ CX,16(DI)
MOVQ R8,24(DI)
MOVQ R9,32(DI)
MOVQ 0(SP),R11
MOVQ 8(SP),R12
MOVQ 16(SP),R13
MOVQ 24(SP),R14
MOVQ 32(SP),R15
MOVQ 40(SP),BX
MOVQ 48(SP),BP
MOVQ R11,SP
MOVQ DI,AX
MOVQ SI,DX
RET

File diff suppressed because it is too large Load diff

View file

@ -3,40 +3,28 @@
// 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
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// 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 a+8(FP), SI
MOVQ b+16(FP), DX
MOVQ SP,R11
MOVQ $31,CX
NOTQ CX
ANDQ CX,SP
ADDQ $32,SP
MOVQ R11,0(SP)
MOVQ R12,8(SP)
MOVQ R13,16(SP)
MOVQ R14,24(SP)
MOVQ R15,32(SP)
MOVQ BX,40(SP)
MOVQ BP,48(SP)
MOVQ DI,56(SP)
MOVQ DX,CX
MOVQ 24(SI),DX
IMUL3Q $19,DX,AX
MOVQ AX,64(SP)
MOVQ AX,0(SP)
MULQ 16(CX)
MOVQ AX,R8
MOVQ DX,R9
MOVQ 32(SI),DX
IMUL3Q $19,DX,AX
MOVQ AX,72(SP)
MOVQ AX,8(SP)
MULQ 8(CX)
ADDQ AX,R8
ADCQ DX,R9
@ -111,11 +99,11 @@ TEXT ·mul(SB),0,$128-24
MULQ 8(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 64(SP),AX
MOVQ 0(SP),AX
MULQ 24(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 64(SP),AX
MOVQ 0(SP),AX
MULQ 32(CX)
ADDQ AX,R12
ADCQ DX,R13
@ -123,19 +111,19 @@ TEXT ·mul(SB),0,$128-24
MULQ 0(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 72(SP),AX
MOVQ 8(SP),AX
MULQ 16(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 72(SP),AX
MOVQ 8(SP),AX
MULQ 24(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 72(SP),AX
MOVQ 8(SP),AX
MULQ 32(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ ·REDMASK51(SB),SI
MOVQ $REDMASK51,SI
SHLQ $13,R9:R8
ANDQ SI,R8
SHLQ $13,R11:R10
@ -178,14 +166,4 @@ TEXT ·mul(SB),0,$128-24
MOVQ R9,16(DI)
MOVQ AX,24(DI)
MOVQ R10,32(DI)
MOVQ 0(SP),R11
MOVQ 8(SP),R12
MOVQ 16(SP),R13
MOVQ 24(SP),R14
MOVQ 32(SP),R15
MOVQ 40(SP),BX
MOVQ 48(SP),BP
MOVQ R11,SP
MOVQ DI,AX
MOVQ SI,DX
RET

View file

@ -3,28 +3,17 @@
// 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
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func square(out, in *[5]uint64)
TEXT ·square(SB),7,$96-16
TEXT ·square(SB),7,$0-16
MOVQ out+0(FP), DI
MOVQ in+8(FP), SI
MOVQ SP,R11
MOVQ $31,CX
NOTQ CX
ANDQ CX,SP
ADDQ $32, SP
MOVQ R11,0(SP)
MOVQ R12,8(SP)
MOVQ R13,16(SP)
MOVQ R14,24(SP)
MOVQ R15,32(SP)
MOVQ BX,40(SP)
MOVQ BP,48(SP)
MOVQ 0(SI),AX
MULQ 0(SI)
MOVQ AX,CX
@ -97,7 +86,7 @@ TEXT ·square(SB),7,$96-16
MULQ 32(SI)
ADDQ AX,R13
ADCQ DX,R14
MOVQ ·REDMASK51(SB),SI
MOVQ $REDMASK51,SI
SHLQ $13,R8:CX
ANDQ SI,CX
SHLQ $13,R10:R9
@ -140,14 +129,4 @@ TEXT ·square(SB),7,$96-16
MOVQ R9,16(DI)
MOVQ AX,24(DI)
MOVQ R10,32(DI)
MOVQ 0(SP),R11
MOVQ 8(SP),R12
MOVQ 16(SP),R13
MOVQ 24(SP),R14
MOVQ 32(SP),R15
MOVQ 40(SP),BX
MOVQ 48(SP),BP
MOVQ R11,SP
MOVQ DI,AX
MOVQ SI,DX
RET

View file

@ -3,20 +3,23 @@
// license that can be found in the LICENSE file.
// 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
// 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
// This code is a port of the public domain, “ref10” implementation of ed25519
// from SUPERCOP.
import (
"bytes"
"crypto"
cryptorand "crypto/rand"
"crypto/sha512"
"crypto/subtle"
"errors"
"io"
"strconv"
@ -31,6 +34,8 @@ const (
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
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.
@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.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.
// Ed25519 performs two passes over messages to be signed and therefore cannot
// 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.
// 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 {
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
}
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[31] &= 127
digest[31] |= 64
@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
privateKey := make([]byte, PrivateKeySize)
copy(privateKey, seed)
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
@ -171,11 +200,18 @@ func Verify(publicKey PublicKey, message, sig []byte) bool {
edwards25519.ScReduce(&hReduced, &digest)
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
R.ToBytes(&checkR)
return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1
return bytes.Equal(sig[:32], checkR[:])
}

View file

@ -4,6 +4,8 @@
package edwards25519
import "encoding/binary"
// This code is a port of the public domain, “ref10” implementation of ed25519
// from SUPERCOP.
@ -1769,3 +1771,23 @@ func ScReduce(out *[32]byte, s *[64]byte) {
out[30] = byte(s11 >> 9)
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
}

View file

@ -10,6 +10,7 @@ import (
"bufio"
"bytes"
"encoding/base64"
"fmt"
"io"
"strings"
"unicode"
@ -89,49 +90,113 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
return
}
line, _, err := l.in.ReadLine()
line, isPrefix, err := l.in.ReadLine()
if err != nil {
return
}
// Entry-level cleanup, just trim spaces.
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 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 |
uint32(expectedBytes[1])<<8 |
uint32(expectedBytes[2])
l.crc = &crc
for {
line, _, err = l.in.ReadLine()
if err != nil && err != io.EOF {
return
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 {
if len(strings.TrimSpace(string(line))) > 0 {
break
}
lineWithChecksum = false
line, _, err = l.in.ReadLine()
if err == io.EOF {
break
}
if !bytes.HasPrefix(line, armorEnd) {
return 0, ArmorCorrupt
if err != nil {
return
}
l.eof = true
return 0, io.EOF
}
expectArmorEnd = true
}
if bytes.HasPrefix(line, armorEnd) {
// Unexpected ending, there was no checksum.
l.eof = true
l.crc = nil
return 0, io.EOF
if lineWithChecksum {
// ArmorEnd and checksum at the same line?
return 0, ArmorCorrupt
}
l.eof = true
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)
bytesToSave := len(line) - n

View file

@ -280,3 +280,37 @@ func Unmarshal(curve elliptic.Curve, data []byte) (x, y *big.Int) {
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
}

View file

@ -70,3 +70,11 @@ type UnknownPacketTypeError uint8
func (upte UnknownPacketTypeError) Error() string {
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)
}

View file

@ -118,7 +118,8 @@ func (e *Entity) primaryIdentity() *Identity {
func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
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
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) {
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 {
if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) &&
subkey.PrivateKey.PrivateKey != nil &&
subkey.PublicKey.PubKeyAlgo.CanSign() &&
!subkey.Sig.KeyExpired(now) &&
subkey.Revocation == nil &&
!subkey.Sig.KeyExpired(now) {
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
candidateSubkey = i
maxTime = subkey.Sig.CreationTime
break
}
}
@ -504,7 +510,7 @@ EachPacket:
// Only register an identity once we've gotten a valid self-signature.
// It's possible therefore for us to throw away `current` in the case
// no valid self-signatures were found. That's OK as long as there are
// other identies that make sense.
// other identities that make sense.
//
// NOTE! We might later see a revocation for this very same UID, and it
// won't be undone. We've preserved this feature from the original
@ -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 {
e.Subkeys = append(e.Subkeys, subKey)
} else {
@ -690,7 +705,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
}
isPrimaryId := true
e.Identities[uid.Id] = &Identity{
Name: uid.Name,
Name: uid.Id,
UserId: uid,
SelfSignature: &packet.Signature{
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[0] = Subkey{
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 {
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 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)
if err != nil {
return

View file

@ -83,6 +83,10 @@ func checksumKeyMaterial(key []byte) uint16 {
// private key must have been decrypted first.
// If config is nil, sensible defaults will be used.
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 b []byte
@ -90,7 +94,8 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
// padding oracle attacks.
switch priv.PubKeyAlgo {
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:
c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)

View file

@ -17,6 +17,7 @@ import (
"github.com/keybase/go-crypto/cast5"
"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
@ -415,6 +416,8 @@ const (
// RFC 6637, Section 5.
PubKeyAlgoECDH PublicKeyAlgorithm = 18
PubKeyAlgoECDSA PublicKeyAlgorithm = 19
PubKeyAlgoBadElGamal PublicKeyAlgorithm = 20 // Reserved (deprecated, formerly ElGamal Encrypt or Sign)
// RFC -1
PubKeyAlgoEdDSA PublicKeyAlgorithm = 22
)
@ -507,19 +510,17 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) {
numBytes := (int(bitLength) + 7) / 8
mpi = make([]byte, numBytes)
_, 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
}
// writeMPI serializes a big integer to w.
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)})
if err == nil {
_, 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())
}
// 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
// supported by OpenPGP (except for BZIP2, which is not currently
// supported). See Section 9.3 of RFC 4880.

View file

@ -44,6 +44,10 @@ type EdDSAPrivateKey struct {
seed parsedMPI
}
func (e *EdDSAPrivateKey) Seed() []byte {
return e.seed.bytes
}
func (e *EdDSAPrivateKey) Sign(digest []byte) (R, S []byte, err error) {
r := bytes.NewReader(e.seed.bytes)
publicKey, privateKey, err := ed25519.GenerateKey(r)
@ -89,6 +93,13 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK
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) {
err = (&pk.PublicKey).parse(r)
if err != nil {
@ -415,8 +426,11 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) {
return pk.parseECDHPrivateKey(data)
case PubKeyAlgoEdDSA:
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) {

View file

@ -27,10 +27,13 @@ import (
"github.com/keybase/go-crypto/openpgp/ecdh"
"github.com/keybase/go-crypto/openpgp/elgamal"
"github.com/keybase/go-crypto/openpgp/errors"
"github.com/keybase/go-crypto/openpgp/s2k"
"github.com/keybase/go-crypto/rsa"
)
var (
// NIST curve P-224
oidCurveP224 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x21}
// NIST curve P-256
oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}
// NIST curve P-384
@ -128,6 +131,8 @@ func (f *ecdsaKey) serialize(w io.Writer) (err error) {
func getCurveByOid(oid []byte) elliptic.Curve {
switch {
case bytes.Equal(oid, oidCurveP224):
return elliptic.P224()
case bytes.Equal(oid, oidCurveP256):
return elliptic.P256()
case bytes.Equal(oid, oidCurveP384):
@ -324,6 +329,30 @@ func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *Public
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 {
pk := &PublicKey{
CreationTime: creationTime,
@ -331,22 +360,34 @@ func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey
PublicKey: pub,
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()
return pk
@ -377,6 +418,9 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
return err
}
err = pk.edk.check()
if err == nil {
pk.PublicKey = ed25519.PublicKey(pk.edk.p.bytes[1:])
}
case PubKeyAlgoECDSA:
pk.ec = new(ecdsaKey)
if err = pk.ec.parse(r); err != nil {
@ -393,6 +437,14 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
return
}
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:
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),
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++ {
rsa.E <<= 8
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.g.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.g.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.g.bytes)
length += 2 + len(pk.y.bytes)
case PubKeyAlgoElGamal:
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
length += 2 + len(pk.p.bytes)
length += 2 + len(pk.g.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)
case PubKeyAlgoDSA:
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)
case PubKeyAlgoECDSA:
return pk.ec.serialize(w)
@ -637,7 +691,7 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
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 {
return errors.SignatureError("RSA verification failure")
}
@ -694,7 +748,7 @@ func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
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
@ -910,7 +964,7 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
bitLength = pk.n.bitLength
case PubKeyAlgoDSA:
bitLength = pk.p.bitLength
case PubKeyAlgoElGamal:
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
bitLength = pk.p.bitLength
case PubKeyAlgoECDH:
ecdhPublicKey := pk.PublicKey.(*ecdh.PublicKey)
@ -928,3 +982,12 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
}
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
}
}

View file

@ -105,6 +105,8 @@ func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) {
return
}
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++ {
rsa.E <<= 8
rsa.E |= int64(pk.e.bytes[i])

View file

@ -10,6 +10,7 @@ import (
"crypto/dsa"
"crypto/ecdsa"
"encoding/binary"
"fmt"
"hash"
"io"
"strconv"
@ -384,6 +385,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
err = errors.StructuralError("empty key flags subpacket")
return
}
if subpacket[0] != 0 {
sig.FlagsValid = true
if subpacket[0]&KeyFlagCertify != 0 {
sig.FlagCertify = true
@ -397,6 +399,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
if subpacket[0]&KeyFlagEncryptStorage != 0 {
sig.FlagEncryptStorage = true
}
}
case reasonForRevocationSubpacket:
// Reason For Revocation, section 5.2.3.23
if !isHashed {
@ -624,6 +627,13 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
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 {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
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]
}
r, s, err := dsa.Sign(config.Random(), dsaPriv, digest)
if err == nil {
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:
r, s, err := ecdsa.Sign(config.Random(), priv.PrivateKey.(*ecdsa.PrivateKey), digest)
if err == nil {
if err != nil {
return err
}
sig.ECDSASigR = FromBig(r)
sig.ECDSASigS = FromBig(s)
}
case PubKeyAlgoEdDSA:
r, s, err := priv.PrivateKey.(*EdDSAPrivateKey).Sign(digest)
if err == nil {
if err != nil {
return err
}
sig.EdDSASigR = FromBytes(r)
sig.EdDSASigS = FromBytes(s)
}
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
@ -704,6 +717,28 @@ func (sig *Signature) SignKeyWithSigner(signeePubKey *PublicKey, signerPubKey *P
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
// called first.
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})
}
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
}

View file

@ -91,10 +91,10 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunc
return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
}
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
}

View file

@ -61,6 +61,9 @@ type MessageDetails struct {
Signature *packet.Signature // the signature packet itself, if v4 (default)
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
}
@ -158,8 +161,15 @@ FindKey:
continue
}
if !pk.key.PrivateKey.Encrypted {
if pk.key.PrivateKey.PrivateKey == nil {
// Key is stubbed
continue
}
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 {
continue
@ -244,8 +254,17 @@ FindLiteralData:
return nil, err
}
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)
@ -329,17 +348,36 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
n, err = scr.md.LiteralData.Body.Read(buf)
scr.wrappedHash.Write(buf[:n])
if err == io.EOF {
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
}
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")
}
}
@ -354,6 +392,12 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
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
// unsigned hash of its own. In order to check this we need to
// close that Reader.

View file

@ -458,7 +458,18 @@ func AttachedSign(out io.WriteCloser, signed Entity, hints *FileHints,
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{
SigType: packet.SigTypeBinary,

2
vendor/modules.txt vendored
View file

@ -253,7 +253,7 @@ github.com/jessevdk/go-flags
github.com/kballard/go-shellquote
# github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd
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/cast5
github.com/keybase/go-crypto/curve25519