cmd/age: add support for encrypted SSH key files

This commit is contained in:
Filippo Valsorda
2019-11-24 19:15:53 -05:00
parent 2cc62919a6
commit c624abc0ad
9 changed files with 198 additions and 16 deletions
+26 -4
View File
@@ -4,6 +4,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
// Package age implements age-tool.com file encryption.
package age
import (
@@ -22,6 +23,13 @@ type Identity interface {
Unwrap(block *format.Recipient) (fileKey []byte, err error)
}
type IdentityMatcher interface {
Identity
Matches(block *format.Recipient) error
}
var ErrIncorrectIdentity = errors.New("incorrect identity for recipient block")
type Recipient interface {
Type() string
Wrap(fileKey []byte) (*format.Recipient, error)
@@ -89,15 +97,29 @@ RecipientsLoop:
return nil, errors.New("an scrypt recipient must be the only one")
}
for _, i := range identities {
if i.Type() != r.Type {
continue
}
fileKey, err = i.Unwrap(r)
if err == nil {
break RecipientsLoop
if i, ok := i.(IdentityMatcher); ok {
err := i.Matches(r)
if err != nil {
if err == ErrIncorrectIdentity {
continue
}
return nil, err
}
}
fileKey, err = i.Unwrap(r)
if err != nil {
if err == ErrIncorrectIdentity {
continue
}
return nil, err
}
break RecipientsLoop
}
}
if fileKey == nil {
+2 -2
View File
@@ -104,7 +104,7 @@ func (i *ScryptIdentity) SetMaxWorkFactor(logN int) {
func (i *ScryptIdentity) Unwrap(block *format.Recipient) ([]byte, error) {
if block.Type != "scrypt" {
return nil, errors.New("wrong recipient block type")
return nil, ErrIncorrectIdentity
}
if len(block.Args) != 2 {
return nil, errors.New("invalid scrypt recipient block")
@@ -134,7 +134,7 @@ func (i *ScryptIdentity) Unwrap(block *format.Recipient) ([]byte, error) {
fileKey, err := aeadDecrypt(k, block.Body)
if err != nil {
return nil, fmt.Errorf("failed to decrypt file key: %v", err)
return nil, ErrIncorrectIdentity
}
return fileKey, nil
}
+4 -4
View File
@@ -98,7 +98,7 @@ func NewSSHRSAIdentity(key *rsa.PrivateKey) (*SSHRSAIdentity, error) {
func (i *SSHRSAIdentity) Unwrap(block *format.Recipient) ([]byte, error) {
if block.Type != "ssh-rsa" {
return nil, errors.New("wrong recipient block type")
return nil, ErrIncorrectIdentity
}
if len(block.Args) != 1 {
return nil, errors.New("invalid ssh-rsa recipient block")
@@ -115,7 +115,7 @@ func (i *SSHRSAIdentity) Unwrap(block *format.Recipient) ([]byte, error) {
h.Write(i.sshKey.Marshal())
hh := h.Sum(nil)
if !bytes.Equal(hh[:4], hash) {
return nil, errors.New("wrong ssh-rsa key")
return nil, ErrIncorrectIdentity
}
fileKey, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, i.k,
@@ -304,7 +304,7 @@ func ed25519PrivateKeyToCurve25519(pk ed25519.PrivateKey) []byte {
func (i *SSHEd25519Identity) Unwrap(block *format.Recipient) ([]byte, error) {
// TODO: DRY this up with the X25519 implementation.
if block.Type != "ssh-ed25519" {
return nil, errors.New("wrong recipient block type")
return nil, ErrIncorrectIdentity
}
if len(block.Args) != 2 {
return nil, errors.New("invalid ssh-ed25519 recipient block")
@@ -328,7 +328,7 @@ func (i *SSHEd25519Identity) Unwrap(block *format.Recipient) ([]byte, error) {
sH.Write(i.sshKey.Marshal())
hh := sH.Sum(nil)
if !bytes.Equal(hh[:4], hash) {
return nil, errors.New("wrong ssh-ed25519 key")
return nil, ErrIncorrectIdentity
}
var sharedSecret, theirPublicKey, tweak [32]byte
+2 -2
View File
@@ -145,7 +145,7 @@ func ParseX25519Identity(s string) (*X25519Identity, error) {
func (i *X25519Identity) Unwrap(block *format.Recipient) ([]byte, error) {
if block.Type != "X25519" {
return nil, errors.New("wrong recipient block type")
return nil, ErrIncorrectIdentity
}
if len(block.Args) != 1 {
return nil, errors.New("invalid X25519 recipient block")
@@ -174,7 +174,7 @@ func (i *X25519Identity) Unwrap(block *format.Recipient) ([]byte, error) {
fileKey, err := aeadDecrypt(wrappingKey, block.Body)
if err != nil {
return nil, fmt.Errorf("failed to decrypt file key: %v", err)
return nil, ErrIncorrectIdentity
}
return fileKey, nil
}
+1
View File
@@ -4,6 +4,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
// Package format implements the age file format.
package format
import (