Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
f0d21a77
Commit
f0d21a77
authored
Jun 10, 2011
by
Adam Langley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crypto/openpgp: add ability to encrypt messages.
R=bradfitz, r CC=golang-dev
https://golang.org/cl/4581051
parent
b5071e92
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
372 additions
and
27 deletions
+372
-27
keys.go
src/pkg/crypto/openpgp/keys.go
+76
-0
encrypted_key.go
src/pkg/crypto/openpgp/packet/encrypted_key.go
+56
-5
encrypted_key_test.go
src/pkg/crypto/openpgp/packet/encrypted_key_test.go
+65
-12
packet.go
src/pkg/crypto/openpgp/packet/packet.go
+22
-2
private_key.go
src/pkg/crypto/openpgp/packet/private_key.go
+1
-1
symmetric_key_encrypted.go
src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
+3
-3
symmetrically_encrypted.go
src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
+2
-2
read.go
src/pkg/crypto/openpgp/read.go
+0
-1
write.go
src/pkg/crypto/openpgp/write.go
+102
-1
write_test.go
src/pkg/crypto/openpgp/write_test.go
+45
-0
No files found.
src/pkg/crypto/openpgp/keys.go
View file @
f0d21a77
...
...
@@ -64,6 +64,78 @@ type KeyRing interface {
DecryptionKeys
()
[]
Key
}
// primaryIdentity returns the Identity marked as primary or the first identity
// if none are so marked.
func
(
e
*
Entity
)
primaryIdentity
()
*
Identity
{
var
firstIdentity
*
Identity
for
_
,
ident
:=
range
e
.
Identities
{
if
firstIdentity
==
nil
{
firstIdentity
=
ident
}
if
ident
.
SelfSignature
.
IsPrimaryId
!=
nil
&&
*
ident
.
SelfSignature
.
IsPrimaryId
{
return
ident
}
}
return
firstIdentity
}
// encryptionKey returns the best candidate Key for encrypting a message to the
// given Entity.
func
(
e
*
Entity
)
encryptionKey
()
Key
{
candidateSubkey
:=
-
1
for
i
,
subkey
:=
range
e
.
Subkeys
{
if
subkey
.
Sig
.
FlagsValid
&&
subkey
.
Sig
.
FlagEncryptCommunications
&&
subkey
.
PublicKey
.
PubKeyAlgo
.
CanEncrypt
()
{
candidateSubkey
=
i
break
}
}
i
:=
e
.
primaryIdentity
()
if
e
.
PrimaryKey
.
PubKeyAlgo
.
CanEncrypt
()
{
// If we don't have any candidate subkeys for encryption and
// the primary key doesn't have any usage metadata then we
// assume that the primary key is ok. Or, if the primary key is
// marked as ok to encrypt to, then we can obviously use it.
if
candidateSubkey
==
-
1
&&
!
i
.
SelfSignature
.
FlagsValid
||
i
.
SelfSignature
.
FlagEncryptCommunications
&&
i
.
SelfSignature
.
FlagsValid
{
return
Key
{
e
,
e
.
PrimaryKey
,
e
.
PrivateKey
,
i
.
SelfSignature
}
}
}
if
candidateSubkey
!=
-
1
{
subkey
:=
e
.
Subkeys
[
candidateSubkey
]
return
Key
{
e
,
subkey
.
PublicKey
,
subkey
.
PrivateKey
,
subkey
.
Sig
}
}
// This Entity appears to be signing only.
return
Key
{}
}
// signingKey return the best candidate Key for signing a message with this
// Entity.
func
(
e
*
Entity
)
signingKey
()
Key
{
candidateSubkey
:=
-
1
for
i
,
subkey
:=
range
e
.
Subkeys
{
if
subkey
.
Sig
.
FlagsValid
&&
subkey
.
Sig
.
FlagSign
&&
subkey
.
PublicKey
.
PubKeyAlgo
.
CanSign
()
{
candidateSubkey
=
i
break
}
}
i
:=
e
.
primaryIdentity
()
// If we have no candidate subkey then we assume that it's ok to sign
// with the primary key.
if
candidateSubkey
==
-
1
||
i
.
SelfSignature
.
FlagsValid
&&
i
.
SelfSignature
.
FlagSign
{
return
Key
{
e
,
e
.
PrimaryKey
,
e
.
PrivateKey
,
i
.
SelfSignature
}
}
subkey
:=
e
.
Subkeys
[
candidateSubkey
]
return
Key
{
e
,
subkey
.
PublicKey
,
subkey
.
PrivateKey
,
subkey
.
Sig
}
}
// An EntityList contains one or more Entities.
type
EntityList
[]
*
Entity
...
...
@@ -199,6 +271,10 @@ func readEntity(packets *packet.Reader) (*Entity, os.Error) {
}
}
if
!
e
.
PrimaryKey
.
PubKeyAlgo
.
CanSign
()
{
return
nil
,
error
.
StructuralError
(
"primary key cannot be used for signatures"
)
}
var
current
*
Identity
EachPacket
:
for
{
...
...
src/pkg/crypto/openpgp/packet/encrypted_key.go
View file @
f0d21a77
...
...
@@ -14,6 +14,8 @@ import (
"strconv"
)
const
encryptedKeyVersion
=
3
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
// section 5.1.
type
EncryptedKey
struct
{
...
...
@@ -30,7 +32,7 @@ func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
if
err
!=
nil
{
return
}
if
buf
[
0
]
!=
3
{
if
buf
[
0
]
!=
encryptedKeyVersion
{
return
error
.
UnsupportedError
(
"unknown EncryptedKey version "
+
strconv
.
Itoa
(
int
(
buf
[
0
])))
}
e
.
KeyId
=
binary
.
BigEndian
.
Uint64
(
buf
[
1
:
9
])
...
...
@@ -42,6 +44,14 @@ func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
return
}
func
checksumKeyMaterial
(
key
[]
byte
)
uint16
{
var
checksum
uint16
for
_
,
v
:=
range
key
{
checksum
+=
uint16
(
v
)
}
return
checksum
}
// DecryptRSA decrypts an RSA encrypted session key with the given private key.
func
(
e
*
EncryptedKey
)
DecryptRSA
(
priv
*
rsa
.
PrivateKey
)
(
err
os
.
Error
)
{
if
e
.
Algo
!=
PubKeyAlgoRSA
&&
e
.
Algo
!=
PubKeyAlgoRSAEncryptOnly
{
...
...
@@ -54,13 +64,54 @@ func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) {
e
.
CipherFunc
=
CipherFunction
(
b
[
0
])
e
.
Key
=
b
[
1
:
len
(
b
)
-
2
]
expectedChecksum
:=
uint16
(
b
[
len
(
b
)
-
2
])
<<
8
|
uint16
(
b
[
len
(
b
)
-
1
])
var
checksum
uint16
for
_
,
v
:=
range
e
.
Key
{
checksum
+=
uint16
(
v
)
}
checksum
:=
checksumKeyMaterial
(
e
.
Key
)
if
checksum
!=
expectedChecksum
{
return
error
.
StructuralError
(
"EncryptedKey checksum incorrect"
)
}
return
}
// SerializeEncryptedKey serializes an encrypted key packet to w that contains
// key, encrypted to pub.
func
SerializeEncryptedKey
(
w
io
.
Writer
,
rand
io
.
Reader
,
pub
*
PublicKey
,
cipherFunc
CipherFunction
,
key
[]
byte
)
os
.
Error
{
var
buf
[
10
]
byte
buf
[
0
]
=
encryptedKeyVersion
binary
.
BigEndian
.
PutUint64
(
buf
[
1
:
9
],
pub
.
KeyId
)
buf
[
9
]
=
byte
(
pub
.
PubKeyAlgo
)
keyBlock
:=
make
([]
byte
,
1
/* cipher type */
+
len
(
key
)
+
2
/* checksum */
)
keyBlock
[
0
]
=
byte
(
cipherFunc
)
copy
(
keyBlock
[
1
:
],
key
)
checksum
:=
checksumKeyMaterial
(
key
)
keyBlock
[
1
+
len
(
key
)]
=
byte
(
checksum
>>
8
)
keyBlock
[
1
+
len
(
key
)
+
1
]
=
byte
(
checksum
)
switch
pub
.
PubKeyAlgo
{
case
PubKeyAlgoRSA
,
PubKeyAlgoRSAEncryptOnly
:
return
serializeEncryptedKeyRSA
(
w
,
rand
,
buf
,
pub
.
PublicKey
.
(
*
rsa
.
PublicKey
),
keyBlock
)
case
PubKeyAlgoDSA
,
PubKeyAlgoRSASignOnly
:
return
error
.
InvalidArgumentError
(
"cannot encrypt to public key of type "
+
strconv
.
Itoa
(
int
(
pub
.
PubKeyAlgo
)))
}
return
error
.
UnsupportedError
(
"encrypting a key to public key of type "
+
strconv
.
Itoa
(
int
(
pub
.
PubKeyAlgo
)))
}
func
serializeEncryptedKeyRSA
(
w
io
.
Writer
,
rand
io
.
Reader
,
header
[
10
]
byte
,
pub
*
rsa
.
PublicKey
,
keyBlock
[]
byte
)
os
.
Error
{
cipherText
,
err
:=
rsa
.
EncryptPKCS1v15
(
rand
,
pub
,
keyBlock
)
if
err
!=
nil
{
return
error
.
InvalidArgumentError
(
"RSA encryption failed: "
+
err
.
String
())
}
packetLen
:=
10
/* header length */
+
2
/* mpi size */
+
len
(
cipherText
)
err
=
serializeHeader
(
w
,
packetTypeEncryptedKey
,
packetLen
)
if
err
!=
nil
{
return
err
}
_
,
err
=
w
.
Write
(
header
[
:
])
if
err
!=
nil
{
return
err
}
return
writeMPI
(
w
,
8
*
uint16
(
len
(
cipherText
)),
cipherText
)
}
src/pkg/crypto/openpgp/packet/encrypted_key_test.go
View file @
f0d21a77
...
...
@@ -6,6 +6,8 @@ package packet
import
(
"big"
"bytes"
"crypto/rand"
"crypto/rsa"
"fmt"
"testing"
...
...
@@ -19,7 +21,21 @@ func bigFromBase10(s string) *big.Int {
return
b
}
func
TestEncryptedKey
(
t
*
testing
.
T
)
{
var
encryptedKeyPub
=
rsa
.
PublicKey
{
E
:
65537
,
N
:
bigFromBase10
(
"115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"
),
}
var
encryptedKeyPriv
=
&
rsa
.
PrivateKey
{
PublicKey
:
encryptedKeyPub
,
D
:
bigFromBase10
(
"32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"
),
}
func
TestDecryptingEncryptedKey
(
t
*
testing
.
T
)
{
const
encryptedKeyHex
=
"c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
const
expectedKeyHex
=
"d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
p
,
err
:=
Read
(
readerFromHex
(
encryptedKeyHex
))
if
err
!=
nil
{
t
.
Errorf
(
"error from Read: %s"
,
err
)
...
...
@@ -36,23 +52,63 @@ func TestEncryptedKey(t *testing.T) {
return
}
pub
:=
rsa
.
PublicKey
{
E
:
65537
,
N
:
bigFromBase10
(
"115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"
),
err
=
ek
.
DecryptRSA
(
encryptedKeyPriv
)
if
err
!=
nil
{
t
.
Errorf
(
"error from DecryptRSA: %s"
,
err
)
return
}
if
ek
.
CipherFunc
!=
CipherAES256
{
t
.
Errorf
(
"unexpected EncryptedKey contents: %#v"
,
ek
)
return
}
keyHex
:=
fmt
.
Sprintf
(
"%x"
,
ek
.
Key
)
if
keyHex
!=
expectedKeyHex
{
t
.
Errorf
(
"bad key, got %s want %x"
,
keyHex
,
expectedKeyHex
)
}
}
func
TestEncryptingEncryptedKey
(
t
*
testing
.
T
)
{
key
:=
[]
byte
{
1
,
2
,
3
,
4
}
const
expectedKeyHex
=
"01020304"
const
keyId
=
42
pub
:=
&
PublicKey
{
PublicKey
:
&
encryptedKeyPub
,
KeyId
:
keyId
,
PubKeyAlgo
:
PubKeyAlgoRSAEncryptOnly
,
}
buf
:=
new
(
bytes
.
Buffer
)
err
:=
SerializeEncryptedKey
(
buf
,
rand
.
Reader
,
pub
,
CipherAES128
,
key
)
if
err
!=
nil
{
t
.
Errorf
(
"error writing encrypted key packet: %s"
,
err
)
}
p
,
err
:=
Read
(
buf
)
if
err
!=
nil
{
t
.
Errorf
(
"error from Read: %s"
,
err
)
return
}
ek
,
ok
:=
p
.
(
*
EncryptedKey
)
if
!
ok
{
t
.
Errorf
(
"didn't parse an EncryptedKey, got %#v"
,
p
)
return
}
priv
:=
&
rsa
.
PrivateKey
{
PublicKey
:
pub
,
D
:
bigFromBase10
(
"32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"
),
if
ek
.
KeyId
!=
keyId
||
ek
.
Algo
!=
PubKeyAlgoRSAEncryptOnly
{
t
.
Errorf
(
"unexpected EncryptedKey contents: %#v"
,
ek
)
return
}
err
=
ek
.
DecryptRSA
(
p
riv
)
err
=
ek
.
DecryptRSA
(
encryptedKeyP
riv
)
if
err
!=
nil
{
t
.
Errorf
(
"error from DecryptRSA: %s"
,
err
)
return
}
if
ek
.
CipherFunc
!=
CipherAES
256
{
if
ek
.
CipherFunc
!=
CipherAES
128
{
t
.
Errorf
(
"unexpected EncryptedKey contents: %#v"
,
ek
)
return
}
...
...
@@ -62,6 +118,3 @@ func TestEncryptedKey(t *testing.T) {
t
.
Errorf
(
"bad key, got %s want %x"
,
keyHex
,
expectedKeyHex
)
}
}
const
encryptedKeyHex
=
"c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
const
expectedKeyHex
=
"d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
src/pkg/crypto/openpgp/packet/packet.go
View file @
f0d21a77
...
...
@@ -376,6 +376,26 @@ const (
PubKeyAlgoDSA
PublicKeyAlgorithm
=
17
)
// CanEncrypt returns true if it's possible to encrypt a message to a public
// key of the given type.
func
(
pka
PublicKeyAlgorithm
)
CanEncrypt
()
bool
{
switch
pka
{
case
PubKeyAlgoRSA
,
PubKeyAlgoRSAEncryptOnly
,
PubKeyAlgoElgamal
:
return
true
}
return
false
}
// CanSign returns true if it's possible for a public key of the given type to
// sign a message.
func
(
pka
PublicKeyAlgorithm
)
CanSign
()
bool
{
switch
pka
{
case
PubKeyAlgoRSA
,
PubKeyAlgoRSASignOnly
,
PubKeyAlgoDSA
:
return
true
}
return
false
}
// CipherFunction represents the different block ciphers specified for OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
type
CipherFunction
uint8
...
...
@@ -387,8 +407,8 @@ const (
CipherAES256
CipherFunction
=
9
)
//
k
eySize returns the key size, in bytes, of cipher.
func
(
cipher
CipherFunction
)
k
eySize
()
int
{
//
K
eySize returns the key size, in bytes, of cipher.
func
(
cipher
CipherFunction
)
K
eySize
()
int
{
switch
cipher
{
case
CipherCAST5
:
return
cast5
.
KeySize
...
...
src/pkg/crypto/openpgp/packet/private_key.go
View file @
f0d21a77
...
...
@@ -181,7 +181,7 @@ func (pk *PrivateKey) Decrypt(passphrase []byte) os.Error {
return
nil
}
key
:=
make
([]
byte
,
pk
.
cipher
.
k
eySize
())
key
:=
make
([]
byte
,
pk
.
cipher
.
K
eySize
())
pk
.
s2k
(
key
,
passphrase
)
block
:=
pk
.
cipher
.
new
(
key
)
cfb
:=
cipher
.
NewCFBDecrypter
(
block
,
pk
.
iv
)
...
...
src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
View file @
f0d21a77
...
...
@@ -42,7 +42,7 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
}
ske
.
CipherFunc
=
CipherFunction
(
buf
[
1
])
if
ske
.
CipherFunc
.
k
eySize
()
==
0
{
if
ske
.
CipherFunc
.
K
eySize
()
==
0
{
return
error
.
UnsupportedError
(
"unknown cipher: "
+
strconv
.
Itoa
(
int
(
buf
[
1
])))
}
...
...
@@ -78,7 +78,7 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
return
nil
}
key
:=
make
([]
byte
,
ske
.
CipherFunc
.
k
eySize
())
key
:=
make
([]
byte
,
ske
.
CipherFunc
.
K
eySize
())
ske
.
s2k
(
key
,
passphrase
)
if
len
(
ske
.
encryptedKey
)
==
0
{
...
...
@@ -109,7 +109,7 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
// given passphrase. The session key is returned and must be passed to
// SerializeSymmetricallyEncrypted.
func
SerializeSymmetricKeyEncrypted
(
w
io
.
Writer
,
rand
io
.
Reader
,
passphrase
[]
byte
,
cipherFunc
CipherFunction
)
(
key
[]
byte
,
err
os
.
Error
)
{
keySize
:=
cipherFunc
.
k
eySize
()
keySize
:=
cipherFunc
.
K
eySize
()
if
keySize
==
0
{
return
nil
,
error
.
UnsupportedError
(
"unknown cipher: "
+
strconv
.
Itoa
(
int
(
cipherFunc
)))
}
...
...
src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
View file @
f0d21a77
...
...
@@ -47,7 +47,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
// packet can be read. An incorrect key can, with high probability, be detected
// immediately and this will result in a KeyIncorrect error being returned.
func
(
se
*
SymmetricallyEncrypted
)
Decrypt
(
c
CipherFunction
,
key
[]
byte
)
(
io
.
ReadCloser
,
os
.
Error
)
{
keySize
:=
c
.
k
eySize
()
keySize
:=
c
.
K
eySize
()
if
keySize
==
0
{
return
nil
,
error
.
UnsupportedError
(
"unknown cipher: "
+
strconv
.
Itoa
(
int
(
c
)))
}
...
...
@@ -255,7 +255,7 @@ func (c noOpCloser) Close() os.Error {
// to w and returns a WriteCloser to which the to-be-encrypted packets can be
// written.
func
SerializeSymmetricallyEncrypted
(
w
io
.
Writer
,
c
CipherFunction
,
key
[]
byte
)
(
contents
io
.
WriteCloser
,
err
os
.
Error
)
{
if
c
.
k
eySize
()
!=
len
(
key
)
{
if
c
.
K
eySize
()
!=
len
(
key
)
{
return
nil
,
error
.
InvalidArgumentError
(
"SymmetricallyEncrypted.Serialize: bad key length"
)
}
writeCloser
:=
noOpCloser
{
w
}
...
...
src/pkg/crypto/openpgp/read.go
View file @
f0d21a77
...
...
@@ -57,7 +57,6 @@ type MessageDetails struct {
// been consumed. Once EOF has been seen, the following fields are
// valid. (An authentication code failure is reported as a
// SignatureError error when reading from UnverifiedBody.)
SignatureError
os
.
Error
// nil if the signature is good.
Signature
*
packet
.
Signature
// the signature packet itself.
...
...
src/pkg/crypto/openpgp/write.go
View file @
f0d21a77
...
...
@@ -9,10 +9,12 @@ import (
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
"crypto/openpgp/s2k"
"crypto/rand"
_
"crypto/sha256"
"io"
"os"
"strconv"
"time"
)
...
...
@@ -98,7 +100,7 @@ type FileHints struct {
}
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
// The resulting WriteCloser
MUST
be closed after the contents of the file have
// The resulting WriteCloser
must
be closed after the contents of the file have
// been written.
func
SymmetricallyEncrypt
(
ciphertext
io
.
Writer
,
passphrase
[]
byte
,
hints
*
FileHints
)
(
plaintext
io
.
WriteCloser
,
err
os
.
Error
)
{
if
hints
==
nil
{
...
...
@@ -115,3 +117,102 @@ func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHi
}
return
packet
.
SerializeLiteral
(
w
,
hints
.
IsBinary
,
hints
.
FileName
,
hints
.
EpochSeconds
)
}
// intersectPreferences mutates and returns a prefix of a that contains only
// the values in the intersection of a and b. The order of a is preserved.
func
intersectPreferences
(
a
[]
uint8
,
b
[]
uint8
)
(
intersection
[]
uint8
)
{
var
j
int
for
_
,
v
:=
range
a
{
for
_
,
v2
:=
range
b
{
if
v
==
v2
{
a
[
j
]
=
v
j
++
break
}
}
}
return
a
[
:
j
]
}
func
hashToHashId
(
h
crypto
.
Hash
)
uint8
{
v
,
ok
:=
s2k
.
HashToHashId
(
h
)
if
!
ok
{
panic
(
"tried to convert unknown hash"
)
}
return
v
}
// Encrypt encrypts a message to a number of recipients and, optionally, signs
// it. (Note: signing is not yet implemented.) hints contains optional
// information, that is also encrypted, that aids the recipients in processing
// the message. The resulting WriteCloser must be closed after the contents of
// the file have been written.
func
Encrypt
(
ciphertext
io
.
Writer
,
to
[]
*
Entity
,
signed
*
Entity
,
hints
*
FileHints
)
(
plaintext
io
.
WriteCloser
,
err
os
.
Error
)
{
// These are the possible ciphers that we'll use for the message.
candidateCiphers
:=
[]
uint8
{
uint8
(
packet
.
CipherAES128
),
uint8
(
packet
.
CipherAES256
),
uint8
(
packet
.
CipherCAST5
),
}
// These are the possible hash functions that we'll use for the signature.
candidateHashes
:=
[]
uint8
{
hashToHashId
(
crypto
.
SHA256
),
hashToHashId
(
crypto
.
SHA512
),
hashToHashId
(
crypto
.
SHA1
),
hashToHashId
(
crypto
.
RIPEMD160
),
}
// In the event that a recipient doesn't specify any supported ciphers
// or hash functions, these are the ones that we assume that every
// implementation supports.
defaultCiphers
:=
candidateCiphers
[
len
(
candidateCiphers
)
-
1
:
]
defaultHashes
:=
candidateHashes
[
len
(
candidateHashes
)
-
1
:
]
encryptKeys
:=
make
([]
Key
,
len
(
to
))
for
i
:=
range
to
{
encryptKeys
[
i
]
=
to
[
i
]
.
encryptionKey
()
if
encryptKeys
[
i
]
.
PublicKey
==
nil
{
return
nil
,
error
.
InvalidArgumentError
(
"cannot encrypt a message to key id "
+
strconv
.
Uitob64
(
to
[
i
]
.
PrimaryKey
.
KeyId
,
16
)
+
" because it has no encryption keys"
)
}
sig
:=
to
[
i
]
.
primaryIdentity
()
.
SelfSignature
preferredSymmetric
:=
sig
.
PreferredSymmetric
if
len
(
preferredSymmetric
)
==
0
{
preferredSymmetric
=
defaultCiphers
}
preferredHashes
:=
sig
.
PreferredHash
if
len
(
preferredHashes
)
==
0
{
preferredHashes
=
defaultHashes
}
candidateCiphers
=
intersectPreferences
(
candidateCiphers
,
preferredSymmetric
)
candidateHashes
=
intersectPreferences
(
candidateHashes
,
preferredHashes
)
}
if
len
(
candidateCiphers
)
==
0
||
len
(
candidateHashes
)
==
0
{
return
nil
,
error
.
InvalidArgumentError
(
"cannot encrypt because recipient set shares no common algorithms"
)
}
cipher
:=
packet
.
CipherFunction
(
candidateCiphers
[
0
])
// hash := s2k.HashIdToHash(candidateHashes[0])
symKey
:=
make
([]
byte
,
cipher
.
KeySize
())
if
_
,
err
:=
io
.
ReadFull
(
rand
.
Reader
,
symKey
);
err
!=
nil
{
return
nil
,
err
}
for
_
,
key
:=
range
encryptKeys
{
if
err
:=
packet
.
SerializeEncryptedKey
(
ciphertext
,
rand
.
Reader
,
key
.
PublicKey
,
cipher
,
symKey
);
err
!=
nil
{
return
nil
,
err
}
}
w
,
err
:=
packet
.
SerializeSymmetricallyEncrypted
(
ciphertext
,
cipher
,
symKey
)
if
err
!=
nil
{
return
}
if
hints
==
nil
{
hints
=
&
FileHints
{}
}
return
packet
.
SerializeLiteral
(
w
,
hints
.
IsBinary
,
hints
.
FileName
,
hints
.
EpochSeconds
)
}
src/pkg/crypto/openpgp/write_test.go
View file @
f0d21a77
...
...
@@ -9,6 +9,7 @@ import (
"crypto/rand"
"os"
"io"
"io/ioutil"
"testing"
"time"
)
...
...
@@ -120,3 +121,47 @@ func TestSymmetricEncryption(t *testing.T) {
t
.
Errorf
(
"recovered message incorrect got '%s', want '%s'"
,
messageBuf
.
Bytes
(),
message
)
}
}
func
TestEncryption
(
t
*
testing
.
T
)
{
kring
,
_
:=
ReadKeyRing
(
readerFromHex
(
testKeys1And2PrivateHex
))
buf
:=
new
(
bytes
.
Buffer
)
w
,
err
:=
Encrypt
(
buf
,
kring
[
:
1
],
nil
,
/* not signed */
nil
/* no hints */
)
if
err
!=
nil
{
t
.
Errorf
(
"error in Encrypt: %s"
,
err
)
return
}
const
message
=
"testing"
_
,
err
=
w
.
Write
([]
byte
(
message
))
if
err
!=
nil
{
t
.
Errorf
(
"error writing plaintext: %s"
,
err
)
return
}
err
=
w
.
Close
()
if
err
!=
nil
{
t
.
Errorf
(
"error closing WriteCloser: %s"
,
err
)
return
}
md
,
err
:=
ReadMessage
(
buf
,
kring
,
nil
/* no prompt */
)
if
err
!=
nil
{
t
.
Errorf
(
"error reading message: %s"
,
err
)
return
}
plaintext
,
err
:=
ioutil
.
ReadAll
(
md
.
UnverifiedBody
)
if
err
!=
nil
{
t
.
Errorf
(
"error reading encrypted contents: %s"
,
err
)
return
}
expectedKeyId
:=
kring
[
0
]
.
encryptionKey
()
.
PublicKey
.
KeyId
if
len
(
md
.
EncryptedToKeyIds
)
!=
1
||
md
.
EncryptedToKeyIds
[
0
]
!=
expectedKeyId
{
t
.
Errorf
(
"expected message to be encrypted to %v, but got %#v"
,
expectedKeyId
,
md
.
EncryptedToKeyIds
)
}
if
string
(
plaintext
)
!=
message
{
t
.
Errorf
(
"got: %s, want: %s"
,
string
(
plaintext
),
message
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment