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
f2e94de6
Commit
f2e94de6
authored
Jun 22, 2011
by
Adam Langley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crypto/openpgp: add ElGamal support.
R=bradfitz, r CC=golang-dev
https://golang.org/cl/4639049
parent
10b5519d
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
418 additions
and
60 deletions
+418
-60
Makefile
src/pkg/Makefile
+1
-0
Makefile
src/pkg/crypto/openpgp/elgamal/Makefile
+11
-0
elgamal.go
src/pkg/crypto/openpgp/elgamal/elgamal.go
+122
-0
elgamal_test.go
src/pkg/crypto/openpgp/elgamal/elgamal_test.go
+49
-0
encrypted_key.go
src/pkg/crypto/openpgp/packet/encrypted_key.go
+61
-10
encrypted_key_test.go
src/pkg/crypto/openpgp/packet/encrypted_key_test.go
+12
-5
packet.go
src/pkg/crypto/openpgp/packet/packet.go
+2
-2
private_key.go
src/pkg/crypto/openpgp/packet/private_key.go
+22
-0
private_key_test.go
src/pkg/crypto/openpgp/packet/private_key_test.go
+30
-10
public_key.go
src/pkg/crypto/openpgp/packet/public_key.go
+41
-2
read.go
src/pkg/crypto/openpgp/read.go
+5
-3
read_test.go
src/pkg/crypto/openpgp/read_test.go
+0
-0
write_test.go
src/pkg/crypto/openpgp/write_test.go
+62
-28
No files found.
src/pkg/Makefile
View file @
f2e94de6
...
...
@@ -45,6 +45,7 @@ DIRS=\
crypto/ocsp
\
crypto/openpgp
\
crypto/openpgp/armor
\
crypto/openpgp/elgamal
\
crypto/openpgp/error
\
crypto/openpgp/packet
\
crypto/openpgp/s2k
\
...
...
src/pkg/crypto/openpgp/elgamal/Makefile
0 → 100644
View file @
f2e94de6
# Copyright 2011 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.
include
../../../../Make.inc
TARG
=
crypto/openpgp/elgamal
GOFILES
=
\
elgamal.go
\
include
../../../../Make.pkg
src/pkg/crypto/openpgp/elgamal/elgamal.go
0 → 100644
View file @
f2e94de6
// Copyright 2011 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.
// Package elgamal implements ElGamal encryption, suitable for OpenPGP,
// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
// n. 4, 1985, pp. 469-472.
//
// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
// unsuitable for other protocols. RSA should be used in preference in any
// case.
package
elgamal
import
(
"big"
"crypto/rand"
"crypto/subtle"
"io"
"os"
)
// PublicKey represents an ElGamal public key.
type
PublicKey
struct
{
G
,
P
,
Y
*
big
.
Int
}
// PrivateKey represents an ElGamal private key.
type
PrivateKey
struct
{
PublicKey
X
*
big
.
Int
}
// Encrypt encrypts the given message to the given public key. The result is a
// pair of integers. Errors can result from reading random, or because msg is
// too large to be encrypted to the public key.
func
Encrypt
(
random
io
.
Reader
,
pub
*
PublicKey
,
msg
[]
byte
)
(
c1
,
c2
*
big
.
Int
,
err
os
.
Error
)
{
pLen
:=
(
pub
.
P
.
BitLen
()
+
7
)
/
8
if
len
(
msg
)
>
pLen
-
11
{
err
=
os
.
ErrorString
(
"elgamal: message too long"
)
return
}
// EM = 0x02 || PS || 0x00 || M
em
:=
make
([]
byte
,
pLen
-
1
)
em
[
0
]
=
2
ps
,
mm
:=
em
[
1
:
len
(
em
)
-
len
(
msg
)
-
1
],
em
[
len
(
em
)
-
len
(
msg
)
:
]
err
=
nonZeroRandomBytes
(
ps
,
random
)
if
err
!=
nil
{
return
}
em
[
len
(
em
)
-
len
(
msg
)
-
1
]
=
0
copy
(
mm
,
msg
)
m
:=
new
(
big
.
Int
)
.
SetBytes
(
em
)
k
,
err
:=
rand
.
Int
(
random
,
pub
.
P
)
if
err
!=
nil
{
return
}
c1
=
new
(
big
.
Int
)
.
Exp
(
pub
.
G
,
k
,
pub
.
P
)
s
:=
new
(
big
.
Int
)
.
Exp
(
pub
.
Y
,
k
,
pub
.
P
)
c2
=
s
.
Mul
(
s
,
m
)
c2
.
Mod
(
c2
,
pub
.
P
)
return
}
// Decrypt takes two integers, resulting from an ElGamal encryption, and
// returns the plaintext of the message. An error can result only if the
// ciphertext is invalid. Users should keep in mind that this is a padding
// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
// Bleichenbacher, Advances in Cryptology (Crypto '98),
func
Decrypt
(
priv
*
PrivateKey
,
c1
,
c2
*
big
.
Int
)
(
msg
[]
byte
,
err
os
.
Error
)
{
s
:=
new
(
big
.
Int
)
.
Exp
(
c1
,
priv
.
X
,
priv
.
P
)
s
.
ModInverse
(
s
,
priv
.
P
)
s
.
Mul
(
s
,
c2
)
s
.
Mod
(
s
,
priv
.
P
)
em
:=
s
.
Bytes
()
firstByteIsTwo
:=
subtle
.
ConstantTimeByteEq
(
em
[
0
],
2
)
// The remainder of the plaintext must be a string of non-zero random
// octets, followed by a 0, followed by the message.
// lookingForIndex: 1 iff we are still looking for the zero.
// index: the offset of the first zero byte.
var
lookingForIndex
,
index
int
lookingForIndex
=
1
for
i
:=
1
;
i
<
len
(
em
);
i
++
{
equals0
:=
subtle
.
ConstantTimeByteEq
(
em
[
i
],
0
)
index
=
subtle
.
ConstantTimeSelect
(
lookingForIndex
&
equals0
,
i
,
index
)
lookingForIndex
=
subtle
.
ConstantTimeSelect
(
equals0
,
0
,
lookingForIndex
)
}
if
firstByteIsTwo
!=
1
||
lookingForIndex
!=
0
||
index
<
9
{
return
nil
,
os
.
ErrorString
(
"elgamal: decryption error"
)
}
return
em
[
index
+
1
:
],
nil
}
// nonZeroRandomBytes fills the given slice with non-zero random octets.
func
nonZeroRandomBytes
(
s
[]
byte
,
rand
io
.
Reader
)
(
err
os
.
Error
)
{
_
,
err
=
io
.
ReadFull
(
rand
,
s
)
if
err
!=
nil
{
return
}
for
i
:=
0
;
i
<
len
(
s
);
i
++
{
for
s
[
i
]
==
0
{
_
,
err
=
io
.
ReadFull
(
rand
,
s
[
i
:
i
+
1
])
if
err
!=
nil
{
return
}
}
}
return
}
src/pkg/crypto/openpgp/elgamal/elgamal_test.go
0 → 100644
View file @
f2e94de6
// Copyright 2011 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.
package
elgamal
import
(
"big"
"bytes"
"crypto/rand"
"testing"
)
// This is the 1024-bit MODP group from RFC 5114, section 2.1:
const
primeHex
=
"B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
const
generatorHex
=
"A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
func
fromHex
(
hex
string
)
*
big
.
Int
{
n
,
ok
:=
new
(
big
.
Int
)
.
SetString
(
hex
,
16
)
if
!
ok
{
panic
(
"failed to parse hex number"
)
}
return
n
}
func
TestEncryptDecrypt
(
t
*
testing
.
T
)
{
priv
:=
&
PrivateKey
{
PublicKey
:
PublicKey
{
G
:
fromHex
(
generatorHex
),
P
:
fromHex
(
primeHex
),
},
X
:
fromHex
(
"42"
),
}
priv
.
Y
=
new
(
big
.
Int
)
.
Exp
(
priv
.
G
,
priv
.
X
,
priv
.
P
)
message
:=
[]
byte
(
"hello world"
)
c1
,
c2
,
err
:=
Encrypt
(
rand
.
Reader
,
&
priv
.
PublicKey
,
message
)
if
err
!=
nil
{
t
.
Errorf
(
"error encrypting: %s"
,
err
)
}
message2
,
err
:=
Decrypt
(
priv
,
c1
,
c2
)
if
err
!=
nil
{
t
.
Errorf
(
"error decrypting: %s"
,
err
)
}
if
!
bytes
.
Equal
(
message2
,
message
)
{
t
.
Errorf
(
"decryption failed, got: %x, want: %x"
,
message2
,
message
)
}
}
src/pkg/crypto/openpgp/packet/encrypted_key.go
View file @
f2e94de6
...
...
@@ -5,6 +5,8 @@
package
packet
import
(
"big"
"crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/rand"
"crypto/rsa"
...
...
@@ -21,9 +23,10 @@ const encryptedKeyVersion = 3
type
EncryptedKey
struct
{
KeyId
uint64
Algo
PublicKeyAlgorithm
Encrypted
[]
byte
CipherFunc
CipherFunction
// only valid after a successful Decrypt
Key
[]
byte
// only valid after a successful Decrypt
encryptedMPI1
,
encryptedMPI2
[]
byte
}
func
(
e
*
EncryptedKey
)
parse
(
r
io
.
Reader
)
(
err
os
.
Error
)
{
...
...
@@ -37,8 +40,15 @@ func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
}
e
.
KeyId
=
binary
.
BigEndian
.
Uint64
(
buf
[
1
:
9
])
e
.
Algo
=
PublicKeyAlgorithm
(
buf
[
9
])
if
e
.
Algo
==
PubKeyAlgoRSA
||
e
.
Algo
==
PubKeyAlgoRSAEncryptOnly
{
e
.
Encrypted
,
_
,
err
=
readMPI
(
r
)
switch
e
.
Algo
{
case
PubKeyAlgoRSA
,
PubKeyAlgoRSAEncryptOnly
:
e
.
encryptedMPI1
,
_
,
err
=
readMPI
(
r
)
case
PubKeyAlgoElGamal
:
e
.
encryptedMPI1
,
_
,
err
=
readMPI
(
r
)
if
err
!=
nil
{
return
}
e
.
encryptedMPI2
,
_
,
err
=
readMPI
(
r
)
}
_
,
err
=
consumeAll
(
r
)
return
...
...
@@ -52,15 +62,29 @@ func checksumKeyMaterial(key []byte) uint16 {
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
{
return
error
.
InvalidArgumentError
(
"EncryptedKey not RSA encrypted"
)
// Decrypt decrypts an encrypted session key with the given private key. The
// private key must have been decrypted first.
func
(
e
*
EncryptedKey
)
Decrypt
(
priv
*
PrivateKey
)
os
.
Error
{
var
err
os
.
Error
var
b
[]
byte
// TODO(agl): use session key decryption routines here to avoid
// padding oracle attacks.
switch
priv
.
PubKeyAlgo
{
case
PubKeyAlgoRSA
,
PubKeyAlgoRSAEncryptOnly
:
b
,
err
=
rsa
.
DecryptPKCS1v15
(
rand
.
Reader
,
priv
.
PrivateKey
.
(
*
rsa
.
PrivateKey
),
e
.
encryptedMPI1
)
case
PubKeyAlgoElGamal
:
c1
:=
new
(
big
.
Int
)
.
SetBytes
(
e
.
encryptedMPI1
)
c2
:=
new
(
big
.
Int
)
.
SetBytes
(
e
.
encryptedMPI2
)
b
,
err
=
elgamal
.
Decrypt
(
priv
.
PrivateKey
.
(
*
elgamal
.
PrivateKey
),
c1
,
c2
)
default
:
err
=
error
.
InvalidArgumentError
(
"cannot decrypted encrypted session key with private key of type "
+
strconv
.
Itoa
(
int
(
priv
.
PubKeyAlgo
)))
}
b
,
err
:=
rsa
.
DecryptPKCS1v15
(
rand
.
Reader
,
priv
,
e
.
Encrypted
)
if
err
!=
nil
{
return
return
err
}
e
.
CipherFunc
=
CipherFunction
(
b
[
0
])
e
.
Key
=
b
[
1
:
len
(
b
)
-
2
]
expectedChecksum
:=
uint16
(
b
[
len
(
b
)
-
2
])
<<
8
|
uint16
(
b
[
len
(
b
)
-
1
])
...
...
@@ -69,7 +93,7 @@ func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) {
return
error
.
StructuralError
(
"EncryptedKey checksum incorrect"
)
}
return
return
nil
}
// SerializeEncryptedKey serializes an encrypted key packet to w that contains
...
...
@@ -90,6 +114,8 @@ func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFu
switch
pub
.
PubKeyAlgo
{
case
PubKeyAlgoRSA
,
PubKeyAlgoRSAEncryptOnly
:
return
serializeEncryptedKeyRSA
(
w
,
rand
,
buf
,
pub
.
PublicKey
.
(
*
rsa
.
PublicKey
),
keyBlock
)
case
PubKeyAlgoElGamal
:
return
serializeEncryptedKeyElGamal
(
w
,
rand
,
buf
,
pub
.
PublicKey
.
(
*
elgamal
.
PublicKey
),
keyBlock
)
case
PubKeyAlgoDSA
,
PubKeyAlgoRSASignOnly
:
return
error
.
InvalidArgumentError
(
"cannot encrypt to public key of type "
+
strconv
.
Itoa
(
int
(
pub
.
PubKeyAlgo
)))
}
...
...
@@ -115,3 +141,28 @@ func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub
}
return
writeMPI
(
w
,
8
*
uint16
(
len
(
cipherText
)),
cipherText
)
}
func
serializeEncryptedKeyElGamal
(
w
io
.
Writer
,
rand
io
.
Reader
,
header
[
10
]
byte
,
pub
*
elgamal
.
PublicKey
,
keyBlock
[]
byte
)
os
.
Error
{
c1
,
c2
,
err
:=
elgamal
.
Encrypt
(
rand
,
pub
,
keyBlock
)
if
err
!=
nil
{
return
error
.
InvalidArgumentError
(
"ElGamal encryption failed: "
+
err
.
String
())
}
packetLen
:=
10
/* header length */
packetLen
+=
2
/* mpi size */
+
(
c1
.
BitLen
()
+
7
)
/
8
packetLen
+=
2
/* mpi size */
+
(
c2
.
BitLen
()
+
7
)
/
8
err
=
serializeHeader
(
w
,
packetTypeEncryptedKey
,
packetLen
)
if
err
!=
nil
{
return
err
}
_
,
err
=
w
.
Write
(
header
[
:
])
if
err
!=
nil
{
return
err
}
err
=
writeBig
(
w
,
c1
)
if
err
!=
nil
{
return
err
}
return
writeBig
(
w
,
c2
)
}
src/pkg/crypto/openpgp/packet/encrypted_key_test.go
View file @
f2e94de6
...
...
@@ -27,11 +27,18 @@ var encryptedKeyPub = rsa.PublicKey{
N
:
bigFromBase10
(
"115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"
),
}
var
encryptedKeyPriv
=
&
rsa
.
PrivateKey
{
var
encryptedKey
RSA
Priv
=
&
rsa
.
PrivateKey
{
PublicKey
:
encryptedKeyPub
,
D
:
bigFromBase10
(
"32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"
),
}
var
encryptedKeyPriv
=
&
PrivateKey
{
PublicKey
:
PublicKey
{
PubKeyAlgo
:
PubKeyAlgoRSA
,
},
PrivateKey
:
encryptedKeyRSAPriv
,
}
func
TestDecryptingEncryptedKey
(
t
*
testing
.
T
)
{
const
encryptedKeyHex
=
"c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
const
expectedKeyHex
=
"d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
...
...
@@ -52,9 +59,9 @@ func TestDecryptingEncryptedKey(t *testing.T) {
return
}
err
=
ek
.
Decrypt
RSA
(
encryptedKeyPriv
)
err
=
ek
.
Decrypt
(
encryptedKeyPriv
)
if
err
!=
nil
{
t
.
Errorf
(
"error from Decrypt
RSA
: %s"
,
err
)
t
.
Errorf
(
"error from Decrypt: %s"
,
err
)
return
}
...
...
@@ -102,9 +109,9 @@ func TestEncryptingEncryptedKey(t *testing.T) {
return
}
err
=
ek
.
Decrypt
RSA
(
encryptedKeyPriv
)
err
=
ek
.
Decrypt
(
encryptedKeyPriv
)
if
err
!=
nil
{
t
.
Errorf
(
"error from Decrypt
RSA
: %s"
,
err
)
t
.
Errorf
(
"error from Decrypt: %s"
,
err
)
return
}
...
...
src/pkg/crypto/openpgp/packet/packet.go
View file @
f2e94de6
...
...
@@ -372,7 +372,7 @@ const (
PubKeyAlgoRSA
PublicKeyAlgorithm
=
1
PubKeyAlgoRSAEncryptOnly
PublicKeyAlgorithm
=
2
PubKeyAlgoRSASignOnly
PublicKeyAlgorithm
=
3
PubKeyAlgoEl
g
amal
PublicKeyAlgorithm
=
16
PubKeyAlgoEl
G
amal
PublicKeyAlgorithm
=
16
PubKeyAlgoDSA
PublicKeyAlgorithm
=
17
)
...
...
@@ -380,7 +380,7 @@ const (
// key of the given type.
func
(
pka
PublicKeyAlgorithm
)
CanEncrypt
()
bool
{
switch
pka
{
case
PubKeyAlgoRSA
,
PubKeyAlgoRSAEncryptOnly
,
PubKeyAlgoEl
g
amal
:
case
PubKeyAlgoRSA
,
PubKeyAlgoRSAEncryptOnly
,
PubKeyAlgoEl
G
amal
:
return
true
}
return
false
...
...
src/pkg/crypto/openpgp/packet/private_key.go
View file @
f2e94de6
...
...
@@ -9,6 +9,7 @@ import (
"bytes"
"crypto/cipher"
"crypto/dsa"
"crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/openpgp/s2k"
"crypto/rsa"
...
...
@@ -224,6 +225,8 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
return
pk
.
parseRSAPrivateKey
(
data
)
case
PubKeyAlgoDSA
:
return
pk
.
parseDSAPrivateKey
(
data
)
case
PubKeyAlgoElGamal
:
return
pk
.
parseElGamalPrivateKey
(
data
)
}
panic
(
"impossible"
)
}
...
...
@@ -277,3 +280,22 @@ func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err os.Error) {
return
nil
}
func
(
pk
*
PrivateKey
)
parseElGamalPrivateKey
(
data
[]
byte
)
(
err
os
.
Error
)
{
pub
:=
pk
.
PublicKey
.
PublicKey
.
(
*
elgamal
.
PublicKey
)
priv
:=
new
(
elgamal
.
PrivateKey
)
priv
.
PublicKey
=
*
pub
buf
:=
bytes
.
NewBuffer
(
data
)
x
,
_
,
err
:=
readMPI
(
buf
)
if
err
!=
nil
{
return
}
priv
.
X
=
new
(
big
.
Int
)
.
SetBytes
(
x
)
pk
.
PrivateKey
=
priv
pk
.
Encrypted
=
false
pk
.
encryptedData
=
nil
return
nil
}
src/pkg/crypto/openpgp/packet/private_key_test.go
View file @
f2e94de6
...
...
@@ -8,30 +8,50 @@ import (
"testing"
)
var
privateKeyTests
=
[]
struct
{
privateKeyHex
string
creationTime
uint32
}{
{
privKeyRSAHex
,
0x4cc349a8
,
},
{
privKeyElGamalHex
,
0x4df9ee1a
,
},
}
func
TestPrivateKeyRead
(
t
*
testing
.
T
)
{
packet
,
err
:=
Read
(
readerFromHex
(
privKeyHex
))
for
i
,
test
:=
range
privateKeyTests
{
packet
,
err
:=
Read
(
readerFromHex
(
test
.
privateKeyHex
))
if
err
!=
nil
{
t
.
Error
(
err
)
return
t
.
Errorf
(
"#%d: failed to parse: %s"
,
i
,
err
)
continue
}
privKey
:=
packet
.
(
*
PrivateKey
)
if
!
privKey
.
Encrypted
{
t
.
Error
(
"private key isn't encrypted"
)
return
t
.
Errorf
(
"#%d: private key isn't encrypted"
,
i
)
continue
}
err
=
privKey
.
Decrypt
([]
byte
(
"testing"
))
if
err
!=
nil
{
t
.
Error
(
err
)
return
t
.
Errorf
(
"#%d: failed to decrypt: %s"
,
i
,
err
)
continue
}
if
privKey
.
CreationTime
!=
0x4cc349a8
||
privKey
.
Encrypted
{
t
.
Errorf
(
"failed to parse, got: %#v"
,
privKey
)
if
privKey
.
CreationTime
!=
test
.
creationTime
||
privKey
.
Encrypted
{
t
.
Errorf
(
"#%d: bad result, got: %#v"
,
i
,
privKey
)
}
}
}
// Generated with `gpg --export-secret-keys "Test Key 2"`
const
privKeyHex
=
"9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
const
privKeyRSAHex
=
"9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
// Generated by `gpg --export-secret-keys` followed by a manual extraction of
// the ElGamal subkey from the packets.
const
privKeyElGamalHex
=
"9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"
src/pkg/crypto/openpgp/packet/public_key.go
View file @
f2e94de6
...
...
@@ -7,6 +7,7 @@ package packet
import
(
"big"
"crypto/dsa"
"crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/rsa"
"crypto/sha1"
...
...
@@ -69,6 +70,8 @@ func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
err
=
pk
.
parseRSA
(
r
)
case
PubKeyAlgoDSA
:
err
=
pk
.
parseDSA
(
r
)
case
PubKeyAlgoElGamal
:
err
=
pk
.
parseElGamal
(
r
)
default
:
err
=
error
.
UnsupportedError
(
"public key type: "
+
strconv
.
Itoa
(
int
(
pk
.
PubKeyAlgo
)))
}
...
...
@@ -117,7 +120,7 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err os.Error) {
return
}
// parse
R
SA parses DSA public key material from the given Reader. See RFC 4880,
// parse
D
SA parses DSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func
(
pk
*
PublicKey
)
parseDSA
(
r
io
.
Reader
)
(
err
os
.
Error
)
{
pk
.
p
.
bytes
,
pk
.
p
.
bitLength
,
err
=
readMPI
(
r
)
...
...
@@ -146,6 +149,30 @@ func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
return
}
// parseElGamal parses ElGamal public key material from the given Reader. See
// RFC 4880, section 5.5.2.
func
(
pk
*
PublicKey
)
parseElGamal
(
r
io
.
Reader
)
(
err
os
.
Error
)
{
pk
.
p
.
bytes
,
pk
.
p
.
bitLength
,
err
=
readMPI
(
r
)
if
err
!=
nil
{
return
}
pk
.
g
.
bytes
,
pk
.
g
.
bitLength
,
err
=
readMPI
(
r
)
if
err
!=
nil
{
return
}
pk
.
y
.
bytes
,
pk
.
y
.
bitLength
,
err
=
readMPI
(
r
)
if
err
!=
nil
{
return
}
elgamal
:=
new
(
elgamal
.
PublicKey
)
elgamal
.
P
=
new
(
big
.
Int
)
.
SetBytes
(
pk
.
p
.
bytes
)
elgamal
.
G
=
new
(
big
.
Int
)
.
SetBytes
(
pk
.
g
.
bytes
)
elgamal
.
Y
=
new
(
big
.
Int
)
.
SetBytes
(
pk
.
y
.
bytes
)
pk
.
PublicKey
=
elgamal
return
}
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
// The prefix is used when calculating a signature over this public key. See
// RFC 4880, section 5.2.4.
...
...
@@ -160,6 +187,10 @@ func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
pLength
+=
2
+
uint16
(
len
(
pk
.
q
.
bytes
))
pLength
+=
2
+
uint16
(
len
(
pk
.
g
.
bytes
))
pLength
+=
2
+
uint16
(
len
(
pk
.
y
.
bytes
))
case
PubKeyAlgoElGamal
:
pLength
+=
2
+
uint16
(
len
(
pk
.
p
.
bytes
))
pLength
+=
2
+
uint16
(
len
(
pk
.
g
.
bytes
))
pLength
+=
2
+
uint16
(
len
(
pk
.
y
.
bytes
))
default
:
panic
(
"unknown public key algorithm"
)
}
...
...
@@ -180,6 +211,12 @@ func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
length
+=
2
+
len
(
pk
.
q
.
bytes
)
length
+=
2
+
len
(
pk
.
g
.
bytes
)
length
+=
2
+
len
(
pk
.
y
.
bytes
)
case
PubKeyAlgoElGamal
:
length
+=
2
+
len
(
pk
.
p
.
bytes
)
length
+=
2
+
len
(
pk
.
g
.
bytes
)
length
+=
2
+
len
(
pk
.
y
.
bytes
)
default
:
panic
(
"unknown public key algorithm"
)
}
err
=
serializeHeader
(
w
,
packetTypePublicKey
,
length
)
...
...
@@ -210,13 +247,15 @@ func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err os.Error) {
return
writeMPIs
(
w
,
pk
.
n
,
pk
.
e
)
case
PubKeyAlgoDSA
:
return
writeMPIs
(
w
,
pk
.
p
,
pk
.
q
,
pk
.
g
,
pk
.
y
)
case
PubKeyAlgoElGamal
:
return
writeMPIs
(
w
,
pk
.
p
,
pk
.
g
,
pk
.
y
)
}
return
error
.
InvalidArgumentError
(
"bad public-key algorithm"
)
}
// CanSign returns true iff this public key can generate signatures
func
(
pk
*
PublicKey
)
CanSign
()
bool
{
return
pk
.
PubKeyAlgo
!=
PubKeyAlgoRSAEncryptOnly
&&
pk
.
PubKeyAlgo
!=
PubKeyAlgoEl
g
amal
return
pk
.
PubKeyAlgo
!=
PubKeyAlgoRSAEncryptOnly
&&
pk
.
PubKeyAlgo
!=
PubKeyAlgoEl
G
amal
}
// VerifySignature returns nil iff sig is a valid signature, made by this
...
...
src/pkg/crypto/openpgp/read.go
View file @
f2e94de6
...
...
@@ -10,7 +10,6 @@ import (
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
"crypto/rsa"
_
"crypto/sha256"
"hash"
"io"
...
...
@@ -111,7 +110,10 @@ ParsePackets:
case
*
packet
.
EncryptedKey
:
// This packet contains the decryption key encrypted to a public key.
md
.
EncryptedToKeyIds
=
append
(
md
.
EncryptedToKeyIds
,
p
.
KeyId
)
if
p
.
Algo
!=
packet
.
PubKeyAlgoRSA
&&
p
.
Algo
!=
packet
.
PubKeyAlgoRSAEncryptOnly
{
switch
p
.
Algo
{
case
packet
.
PubKeyAlgoRSA
,
packet
.
PubKeyAlgoRSAEncryptOnly
,
packet
.
PubKeyAlgoElGamal
:
break
default
:
continue
}
var
keys
[]
Key
...
...
@@ -154,7 +156,7 @@ FindKey:
}
if
!
pk
.
key
.
PrivateKey
.
Encrypted
{
if
len
(
pk
.
encryptedKey
.
Key
)
==
0
{
pk
.
encryptedKey
.
Decrypt
RSA
(
pk
.
key
.
PrivateKey
.
PrivateKey
.
(
*
rsa
.
PrivateKey
)
)
pk
.
encryptedKey
.
Decrypt
(
pk
.
key
.
PrivateKey
)
}
if
len
(
pk
.
encryptedKey
.
Key
)
==
0
{
continue
...
...
src/pkg/crypto/openpgp/read_test.go
View file @
f2e94de6
This diff is collapsed.
Click to expand it.
src/pkg/crypto/openpgp/write_test.go
View file @
f2e94de6
...
...
@@ -122,78 +122,112 @@ func TestSymmetricEncryption(t *testing.T) {
}
}
func
testEncryption
(
t
*
testing
.
T
,
isSigned
bool
)
{
kring
,
_
:=
ReadKeyRing
(
readerFromHex
(
testKeys1And2PrivateHex
))
var
testEncryptionTests
=
[]
struct
{
keyRingHex
string
isSigned
bool
}{
{
testKeys1And2PrivateHex
,
false
,
},
{
testKeys1And2PrivateHex
,
true
,
},
{
dsaElGamalTestKeysHex
,
false
,
},
{
dsaElGamalTestKeysHex
,
true
,
},
}
func
TestEncryption
(
t
*
testing
.
T
)
{
for
i
,
test
:=
range
testEncryptionTests
{
kring
,
_
:=
ReadKeyRing
(
readerFromHex
(
test
.
keyRingHex
))
passphrase
:=
[]
byte
(
"passphrase"
)
for
_
,
entity
:=
range
kring
{
if
entity
.
PrivateKey
!=
nil
&&
entity
.
PrivateKey
.
Encrypted
{
err
:=
entity
.
PrivateKey
.
Decrypt
(
passphrase
)
if
err
!=
nil
{
t
.
Errorf
(
"#%d: failed to decrypt key"
,
i
)
}
}
for
_
,
subkey
:=
range
entity
.
Subkeys
{
if
subkey
.
PrivateKey
!=
nil
&&
subkey
.
PrivateKey
.
Encrypted
{
err
:=
subkey
.
PrivateKey
.
Decrypt
(
passphrase
)
if
err
!=
nil
{
t
.
Errorf
(
"#%d: failed to decrypt subkey"
,
i
)
}
}
}
}
var
signed
*
Entity
if
isSigned
{
if
test
.
isSigned
{
signed
=
kring
[
0
]
}
buf
:=
new
(
bytes
.
Buffer
)
w
,
err
:=
Encrypt
(
buf
,
kring
[
:
1
],
signed
,
nil
/* no hints */
)
if
err
!=
nil
{
t
.
Errorf
(
"error in Encrypt: %s"
,
err
)
return
t
.
Errorf
(
"#%d: error in Encrypt: %s"
,
i
,
err
)
continue
}
const
message
=
"testing"
_
,
err
=
w
.
Write
([]
byte
(
message
))
if
err
!=
nil
{
t
.
Errorf
(
"error writing plaintext: %s"
,
err
)
return
t
.
Errorf
(
"#%d: error writing plaintext: %s"
,
i
,
err
)
continue
}
err
=
w
.
Close
()
if
err
!=
nil
{
t
.
Errorf
(
"error closing WriteCloser: %s"
,
err
)
return
t
.
Errorf
(
"#%d: error closing WriteCloser: %s"
,
i
,
err
)
continue
}
md
,
err
:=
ReadMessage
(
buf
,
kring
,
nil
/* no prompt */
)
if
err
!=
nil
{
t
.
Errorf
(
"error reading message: %s"
,
err
)
return
t
.
Errorf
(
"#%d: error reading message: %s"
,
i
,
err
)
continue
}
if
isSigned
{
if
test
.
isSigned
{
expectedKeyId
:=
kring
[
0
]
.
signingKey
()
.
PublicKey
.
KeyId
if
md
.
SignedByKeyId
!=
expectedKeyId
{
t
.
Errorf
(
"message signed by wrong key id, got: %d, want: %d"
,
*
md
.
SignedBy
,
expectedKeyId
)
t
.
Errorf
(
"#%d: message signed by wrong key id, got: %d, want: %d"
,
i
,
*
md
.
SignedBy
,
expectedKeyId
)
}
if
md
.
SignedBy
==
nil
{
t
.
Errorf
(
"failed to find the signing Entity"
)
t
.
Errorf
(
"#%d: failed to find the signing Entity"
,
i
)
}
}
plaintext
,
err
:=
ioutil
.
ReadAll
(
md
.
UnverifiedBody
)
if
err
!=
nil
{
t
.
Errorf
(
"error reading encrypted contents: %s"
,
err
)
return
t
.
Errorf
(
"#%d: error reading encrypted contents: %s"
,
i
,
err
)
continue
}
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
)
t
.
Errorf
(
"#%d: expected message to be encrypted to %v, but got %#v"
,
i
,
expectedKeyId
,
md
.
EncryptedToKeyIds
)
}
if
string
(
plaintext
)
!=
message
{
t
.
Errorf
(
"got: %s, want: %s"
,
string
(
plaintext
),
message
)
t
.
Errorf
(
"#%d: got: %s, want: %s"
,
i
,
string
(
plaintext
),
message
)
}
if
isSigned
{
if
test
.
isSigned
{
if
md
.
SignatureError
!=
nil
{
t
.
Errorf
(
"signature error: %s"
,
err
)
t
.
Errorf
(
"#%d: signature error: %s"
,
i
,
err
)
}
if
md
.
Signature
==
nil
{
t
.
Error
(
"signature missing"
)
}
}
}
func
TestEncryption
(
t
*
testing
.
T
)
{
testEncryption
(
t
,
false
/* not signed */
)
}
func
TestEncryptAndSign
(
t
*
testing
.
T
)
{
testEncryption
(
t
,
true
/* signed */
)
}
}
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