Merge pull request #5301 from hashicorp/pkcs12redux
Replace pkcs12 code with upstream
This commit is contained in:
commit
3eeb722897
|
@ -1,9 +0,0 @@
|
|||
This is a fork of the from the original PKCS#12 parsing code
|
||||
published in the Azure repository [go-pkcs12](https://github.com/Azure/go-pkcs12).
|
||||
This fork adds serializing a x509 certificate and private key as PKCS#12 binary blob
|
||||
(aka .PFX file). Due to the specific nature of this code it was not accepted for
|
||||
inclusion in the official Go crypto repository.
|
||||
|
||||
The methods used for decoding PKCS#12 have been moved to the test files to further
|
||||
discourage the use of this library for decoding. Please use the official
|
||||
[pkcs12](https://godoc.org/golang.org/x/crypto/pkcs12) library for decode support.
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
|
@ -5,6 +9,7 @@ import (
|
|||
"unicode/utf16"
|
||||
)
|
||||
|
||||
// bmpString returns s encoded in UCS-2 with a zero terminator.
|
||||
func bmpString(s string) ([]byte, error) {
|
||||
// References:
|
||||
// https://tools.ietf.org/html/rfc7292#appendix-B.1
|
||||
|
@ -13,14 +18,33 @@ func bmpString(s string) ([]byte, error) {
|
|||
// EncodeRune returns 0xfffd if the rune does not need special encoding
|
||||
// - the above RFC provides the info that BMPStrings are NULL terminated.
|
||||
|
||||
rv := make([]byte, 0, 2*len(s)+2)
|
||||
ret := make([]byte, 0, 2*len(s)+2)
|
||||
|
||||
for _, r := range s {
|
||||
if t, _ := utf16.EncodeRune(r); t != 0xfffd {
|
||||
return nil, errors.New("string contains characters that cannot be encoded in UCS-2")
|
||||
return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2")
|
||||
}
|
||||
rv = append(rv, byte(r/256), byte(r%256))
|
||||
ret = append(ret, byte(r/256), byte(r%256))
|
||||
}
|
||||
rv = append(rv, 0, 0)
|
||||
return rv, nil
|
||||
|
||||
return append(ret, 0, 0), nil
|
||||
}
|
||||
|
||||
func decodeBMPString(bmpString []byte) (string, error) {
|
||||
if len(bmpString)%2 != 0 {
|
||||
return "", errors.New("pkcs12: odd-length BMP string")
|
||||
}
|
||||
|
||||
// strip terminator if present
|
||||
if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
|
||||
bmpString = bmpString[:l-2]
|
||||
}
|
||||
|
||||
s := make([]uint16, 0, len(bmpString)/2)
|
||||
for len(bmpString) > 0 {
|
||||
s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
|
||||
bmpString = bmpString[2:]
|
||||
}
|
||||
|
||||
return string(utf16.Decode(s)), nil
|
||||
}
|
||||
|
|
|
@ -1,70 +1,69 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
func decodeBMPString(bmpString []byte) (string, error) {
|
||||
if len(bmpString)%2 != 0 {
|
||||
return "", errors.New("expected BMP byte string to be an even length")
|
||||
}
|
||||
|
||||
// strip terminator if present
|
||||
if terminator := bmpString[len(bmpString)-2:]; terminator[0] == terminator[1] && terminator[1] == 0 {
|
||||
bmpString = bmpString[:len(bmpString)-2]
|
||||
}
|
||||
|
||||
s := make([]uint16, 0, len(bmpString)/2)
|
||||
for len(bmpString) > 0 {
|
||||
s = append(s, uint16(bmpString[0])*265+uint16(bmpString[1]))
|
||||
bmpString = bmpString[2:]
|
||||
}
|
||||
|
||||
return string(utf16.Decode(s)), nil
|
||||
var bmpStringTests = []struct {
|
||||
in string
|
||||
expectedHex string
|
||||
shouldFail bool
|
||||
}{
|
||||
{"", "0000", false},
|
||||
// Example from https://tools.ietf.org/html/rfc7292#appendix-B.
|
||||
{"Beavis", "0042006500610076006900730000", false},
|
||||
// Some characters from the "Letterlike Symbols Unicode block".
|
||||
{"\u2115 - Double-struck N", "21150020002d00200044006f00750062006c0065002d00730074007200750063006b0020004e0000", false},
|
||||
// any character outside the BMP should trigger an error.
|
||||
{"\U0001f000 East wind (Mahjong)", "", true},
|
||||
}
|
||||
|
||||
func TestBMPStringDecode(t *testing.T) {
|
||||
_, err := decodeBMPString([]byte("a"))
|
||||
if err == nil {
|
||||
t.Fatal("expected decode to fail, but it succeeded")
|
||||
if _, err := decodeBMPString([]byte("a")); err == nil {
|
||||
t.Fatalf("expected decode to fail, but it succeeded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBMPString(t *testing.T) {
|
||||
str, err := bmpString("")
|
||||
if !bytes.Equal(str, []byte{0, 0}) {
|
||||
t.Errorf("expected empty string to return double 0, but found: % x", str)
|
||||
}
|
||||
for i, test := range bmpStringTests {
|
||||
expected, err := hex.DecodeString(test.expectedHex)
|
||||
if err != nil {
|
||||
t.Errorf("err: %v", err)
|
||||
t.Fatalf("#%d: failed to decode expectation", i)
|
||||
}
|
||||
|
||||
// Example from https://tools.ietf.org/html/rfc7292#appendix-B
|
||||
str, err = bmpString("Beavis")
|
||||
if !bytes.Equal(str, []byte{0x00, 0x42, 0x00, 0x65, 0x00, 0x61, 0x00, 0x0076, 0x00, 0x69, 0x00, 0x73, 0x00, 0x00}) {
|
||||
t.Errorf("expected 'Beavis' to return 0x00 0x42 0x00 0x65 0x00 0x61 0x00 0x76 0x00 0x69 0x00 0x73 0x00 0x00, but found: % x", str)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %v", err)
|
||||
out, err := bmpString(test.in)
|
||||
if err == nil && test.shouldFail {
|
||||
t.Errorf("#%d: expected to fail, but produced %x", i, out)
|
||||
continue
|
||||
}
|
||||
|
||||
// some characters from the "Letterlike Symbols Unicode block"
|
||||
tst := "\u2115 - Double-struck N"
|
||||
str, err = bmpString(tst)
|
||||
if !bytes.Equal(str, []byte{0x21, 0x15, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x75, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x4e, 0x00, 0x00}) {
|
||||
t.Errorf("expected '%s' to return 0x21 0x15 0x00 0x20 0x00 0x2d 0x00 0x20 0x00 0x44 0x00 0x6f 0x00 0x75 0x00 0x62 0x00 0x6c 0x00 0x65 0x00 0x2d 0x00 0x73 0x00 0x74 0x00 0x72 0x00 0x75 0x00 0x63 0x00 0x6b 0x00 0x20 0x00 0x4e 0x00 0x00, but found: % x", tst, str)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %v", err)
|
||||
if err != nil && !test.shouldFail {
|
||||
t.Errorf("#%d: failed unexpectedly: %s", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// some character outside the BMP should error
|
||||
tst = "\U0001f000 East wind (Mahjong)"
|
||||
_, err = bmpString(tst)
|
||||
if err == nil {
|
||||
t.Errorf("expected '%s' to throw error because the first character is not in the BMP", tst)
|
||||
if !test.shouldFail {
|
||||
if !bytes.Equal(out, expected) {
|
||||
t.Errorf("#%d: expected %s, got %x", i, test.expectedHex, out)
|
||||
continue
|
||||
}
|
||||
|
||||
roundTrip, err := decodeBMPString(out)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: decoding output gave an error: %s", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if roundTrip != test.in {
|
||||
t.Errorf("#%d: decoding output resulted in %q, but it should have been %q", i, roundTrip, test.in)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// implementation of https://tools.ietf.org/html/rfc2898#section-6.1.2
|
||||
// Copyright 2015 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 pkcs12
|
||||
|
||||
|
@ -15,31 +17,52 @@ import (
|
|||
"github.com/hashicorp/packer/builder/azure/pkcs12/rc2"
|
||||
)
|
||||
|
||||
const (
|
||||
pbeWithSHAAnd3KeyTripleDESCBC = "pbeWithSHAAnd3-KeyTripleDES-CBC"
|
||||
pbewithSHAAnd40BitRC2CBC = "pbewithSHAAnd40BitRC2-CBC"
|
||||
)
|
||||
|
||||
const (
|
||||
pbeIterationCount = 2048
|
||||
pbeSaltSizeBytes = 8
|
||||
)
|
||||
|
||||
var (
|
||||
oidPbeWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 12, 1, 3}
|
||||
oidPbewithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 12, 1, 6}
|
||||
oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
|
||||
oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6})
|
||||
)
|
||||
|
||||
var algByOID = map[string]string{
|
||||
oidPbeWithSHAAnd3KeyTripleDESCBC.String(): pbeWithSHAAnd3KeyTripleDESCBC,
|
||||
oidPbewithSHAAnd40BitRC2CBC.String(): pbewithSHAAnd40BitRC2CBC,
|
||||
// pbeCipher is an abstraction of a PKCS#12 cipher.
|
||||
type pbeCipher interface {
|
||||
// create returns a cipher.Block given a key.
|
||||
create(key []byte) (cipher.Block, error)
|
||||
// deriveKey returns a key derived from the given password and salt.
|
||||
deriveKey(salt, password []byte, iterations int) []byte
|
||||
// deriveKey returns an IV derived from the given password and salt.
|
||||
deriveIV(salt, password []byte, iterations int) []byte
|
||||
}
|
||||
|
||||
var blockcodeByAlg = map[string]func(key []byte) (cipher.Block, error){
|
||||
pbeWithSHAAnd3KeyTripleDESCBC: des.NewTripleDESCipher,
|
||||
pbewithSHAAnd40BitRC2CBC: func(key []byte) (cipher.Block, error) {
|
||||
type shaWithTripleDESCBC struct{}
|
||||
|
||||
func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) {
|
||||
return des.NewTripleDESCipher(key)
|
||||
}
|
||||
|
||||
func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24)
|
||||
}
|
||||
|
||||
func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
|
||||
}
|
||||
|
||||
type shaWith40BitRC2CBC struct{}
|
||||
|
||||
func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) {
|
||||
return rc2.New(key, len(key)*8)
|
||||
},
|
||||
}
|
||||
|
||||
func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5)
|
||||
}
|
||||
|
||||
func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
|
||||
}
|
||||
|
||||
type pbeParams struct {
|
||||
|
@ -47,6 +70,67 @@ type pbeParams struct {
|
|||
Iterations int
|
||||
}
|
||||
|
||||
func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) {
|
||||
var cipherType pbeCipher
|
||||
|
||||
switch {
|
||||
case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC):
|
||||
cipherType = shaWithTripleDESCBC{}
|
||||
case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC):
|
||||
cipherType = shaWith40BitRC2CBC{}
|
||||
default:
|
||||
return nil, 0, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported")
|
||||
}
|
||||
|
||||
var params pbeParams
|
||||
if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
key := cipherType.deriveKey(params.Salt, password, params.Iterations)
|
||||
iv := cipherType.deriveIV(params.Salt, password, params.Iterations)
|
||||
|
||||
block, err := cipherType.create(key)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil
|
||||
}
|
||||
|
||||
func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) {
|
||||
cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encrypted := info.Data()
|
||||
if len(encrypted) == 0 {
|
||||
return nil, errors.New("pkcs12: empty encrypted data")
|
||||
}
|
||||
if len(encrypted)%blockSize != 0 {
|
||||
return nil, errors.New("pkcs12: input is not a multiple of the block size")
|
||||
}
|
||||
decrypted = make([]byte, len(encrypted))
|
||||
cbc.CryptBlocks(decrypted, encrypted)
|
||||
|
||||
psLen := int(decrypted[len(decrypted)-1])
|
||||
if psLen == 0 || psLen > blockSize {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
|
||||
if len(decrypted) < psLen {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
ps := decrypted[len(decrypted)-psLen:]
|
||||
decrypted = decrypted[:len(decrypted)-psLen]
|
||||
if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func pad(src []byte, blockSize int) []byte {
|
||||
paddingLength := blockSize - len(src)%blockSize
|
||||
paddingText := bytes.Repeat([]byte{byte(paddingLength)}, paddingLength)
|
||||
|
@ -54,15 +138,15 @@ func pad(src []byte, blockSize int) []byte {
|
|||
}
|
||||
|
||||
func pbEncrypt(plainText, salt, password []byte, iterations int) (cipherText []byte, err error) {
|
||||
_, err = io.ReadFull(rand.Reader, salt)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||
return nil, errors.New("pkcs12: failed to create a random salt value: " + err.Error())
|
||||
}
|
||||
|
||||
key := deriveKeyByAlg[pbeWithSHAAnd3KeyTripleDESCBC](salt, password, iterations)
|
||||
iv := deriveIVByAlg[pbeWithSHAAnd3KeyTripleDESCBC](salt, password, iterations)
|
||||
cipherType := shaWithTripleDESCBC{}
|
||||
key := cipherType.deriveKey(salt, password, iterations)
|
||||
iv := cipherType.deriveIV(salt, password, iterations)
|
||||
|
||||
block, err := des.NewTripleDESCipher(key)
|
||||
block, err := cipherType.create(key)
|
||||
if err != nil {
|
||||
return nil, errors.New("pkcs12: failed to create a block cipher: " + err.Error())
|
||||
}
|
||||
|
@ -76,7 +160,8 @@ func pbEncrypt(plainText, salt, password []byte, iterations int) (cipherText []b
|
|||
return cipherText, nil
|
||||
}
|
||||
|
||||
// decryptable abstracts a object that contains ciphertext.
|
||||
type decryptable interface {
|
||||
GetAlgorithm() pkix.AlgorithmIdentifier
|
||||
GetData() []byte
|
||||
Algorithm() pkix.AlgorithmIdentifier
|
||||
Data() []byte
|
||||
}
|
||||
|
|
|
@ -1,60 +1,19 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, error) {
|
||||
algorithmName, supported := algByOID[algorithm.Algorithm.String()]
|
||||
if !supported {
|
||||
return nil, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported")
|
||||
}
|
||||
|
||||
var params pbeParams
|
||||
if _, err := asn1.Unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k := deriveKeyByAlg[algorithmName](params.Salt, password, params.Iterations)
|
||||
iv := deriveIVByAlg[algorithmName](params.Salt, password, params.Iterations)
|
||||
|
||||
code, err := blockcodeByAlg[algorithmName](k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cbc := cipher.NewCBCDecrypter(code, iv)
|
||||
return cbc, nil
|
||||
}
|
||||
|
||||
func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) {
|
||||
cbc, err := pbDecrypterFor(info.GetAlgorithm(), password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encrypted := info.GetData()
|
||||
|
||||
decrypted = make([]byte, len(encrypted))
|
||||
cbc.CryptBlocks(decrypted, encrypted)
|
||||
|
||||
if psLen := int(decrypted[len(decrypted)-1]); psLen > 0 && psLen <= cbc.BlockSize() {
|
||||
m := decrypted[:len(decrypted)-psLen]
|
||||
ps := decrypted[len(decrypted)-psLen:]
|
||||
if !bytes.Equal(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
decrypted = m
|
||||
} else {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
var sha1WithTripleDES = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
|
||||
|
||||
func TestPbDecrypterFor(t *testing.T) {
|
||||
params, _ := asn1.Marshal(pbeParams{
|
||||
|
@ -70,70 +29,122 @@ func TestPbDecrypterFor(t *testing.T) {
|
|||
|
||||
pass, _ := bmpString("Sesame open")
|
||||
|
||||
_, err := pbDecrypterFor(alg, pass)
|
||||
_, _, err := pbDecrypterFor(alg, pass)
|
||||
if _, ok := err.(NotImplementedError); !ok {
|
||||
t.Errorf("expected not implemented error, got: %T %s", err, err)
|
||||
}
|
||||
|
||||
alg.Algorithm = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
|
||||
cbc, err := pbDecrypterFor(alg, pass)
|
||||
alg.Algorithm = sha1WithTripleDES
|
||||
cbc, blockSize, err := pbDecrypterFor(alg, pass)
|
||||
if err != nil {
|
||||
t.Errorf("err: %v", err)
|
||||
t.Errorf("unexpected error from pbDecrypterFor %v", err)
|
||||
}
|
||||
if blockSize != 8 {
|
||||
t.Errorf("unexpected block size %d, wanted 8", blockSize)
|
||||
}
|
||||
|
||||
M := []byte{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
expectedM := []byte{185, 73, 135, 249, 137, 1, 122, 247}
|
||||
cbc.CryptBlocks(M, M)
|
||||
plaintext := []byte{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
expectedCiphertext := []byte{185, 73, 135, 249, 137, 1, 122, 247}
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
cbc.CryptBlocks(ciphertext, plaintext)
|
||||
|
||||
if !bytes.Equal(M, expectedM) {
|
||||
t.Errorf("expected M to be '%d', but found '%d", expectedM, M)
|
||||
if bytes.Compare(ciphertext, expectedCiphertext) != 0 {
|
||||
t.Errorf("bad ciphertext, got %x but wanted %x", ciphertext, expectedCiphertext)
|
||||
}
|
||||
}
|
||||
|
||||
var pbDecryptTests = []struct {
|
||||
in []byte
|
||||
expected []byte
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
[]byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\xa0\x9a\xdf\x5a\x58\xa0\xea\x46"), // 7 padding bytes
|
||||
[]byte("A secret!"),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
[]byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\x96\x24\x2f\x71\x7e\x32\x3f\xe7"), // 8 padding bytes
|
||||
[]byte("A secret"),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
[]byte("\x35\x0c\xc0\x8d\xab\xa9\x5d\x30\x7f\x9a\xec\x6a\xd8\x9b\x9c\xd9"), // 9 padding bytes, incorrect
|
||||
nil,
|
||||
ErrDecryption,
|
||||
},
|
||||
{
|
||||
[]byte("\xb2\xf9\x6e\x06\x60\xae\x20\xcf\x08\xa0\x7b\xd9\x6b\x20\xef\x41"), // incorrect padding bytes: [ ... 0x04 0x02 ]
|
||||
nil,
|
||||
ErrDecryption,
|
||||
},
|
||||
}
|
||||
|
||||
func TestPbDecrypt(t *testing.T) {
|
||||
salt := []byte("\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8")
|
||||
|
||||
tests := [][]byte{
|
||||
[]byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\xa0\x9a\xdf\x5a\x58\xa0\xea\x46"), // 7 padding bytes
|
||||
[]byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\x96\x24\x2f\x71\x7e\x32\x3f\xe7"), // 8 padding bytes
|
||||
[]byte("\x35\x0c\xc0\x8d\xab\xa9\x5d\x30\x7f\x9a\xec\x6a\xd8\x9b\x9c\xd9"), // 9 padding bytes, incorrect
|
||||
[]byte("\xb2\xf9\x6e\x06\x60\xae\x20\xcf\x08\xa0\x7b\xd9\x6b\x20\xef\x41"), // incorrect padding bytes: [ ... 0x04 0x02 ]
|
||||
}
|
||||
expected := []interface{}{
|
||||
[]byte("A secret!"),
|
||||
[]byte("A secret"),
|
||||
ErrDecryption,
|
||||
ErrDecryption,
|
||||
for i, test := range pbDecryptTests {
|
||||
decryptable := makeTestDecryptable(test.in, salt)
|
||||
password, _ := bmpString("sesame")
|
||||
|
||||
plaintext, err := pbDecrypt(decryptable, password)
|
||||
if err != test.expectedError {
|
||||
t.Errorf("#%d: got error %q, but wanted %q", i, err, test.expectedError)
|
||||
continue
|
||||
}
|
||||
|
||||
for i, c := range tests {
|
||||
td := testDecryptable{
|
||||
data: c,
|
||||
if !bytes.Equal(plaintext, test.expected) {
|
||||
t.Errorf("#%d: got %x, but wanted %x", i, plaintext, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundTripPkc12EncryptDecrypt(t *testing.T) {
|
||||
salt := []byte{0xfe, 0xee, 0xfa, 0xce}
|
||||
password := salt
|
||||
|
||||
// Sweep the possible padding lengths
|
||||
for i := 0; i < 9; i++ {
|
||||
bs := make([]byte, i)
|
||||
_, err := io.ReadFull(rand.Reader, bs)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read: %s", err)
|
||||
}
|
||||
|
||||
cipherText, err := pbEncrypt(bs, salt, password, 4096)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to encrypt: %s\n", err)
|
||||
}
|
||||
|
||||
if len(cipherText)%8 != 0 {
|
||||
t.Fatalf("plain text was not padded as expected")
|
||||
}
|
||||
|
||||
decryptable := makeTestDecryptable(cipherText, salt)
|
||||
plainText, err := pbDecrypt(decryptable, password)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decrypt: %s\n", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(bs, plainText) {
|
||||
t.Fatalf("got %x, but wanted %x", bs, plainText)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeTestDecryptable(bytes, salt []byte) testDecryptable {
|
||||
decryptable := testDecryptable{
|
||||
data: bytes,
|
||||
algorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}), // SHA1/3TDES
|
||||
Algorithm: sha1WithTripleDES,
|
||||
Parameters: pbeParams{
|
||||
Salt: []byte("\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8"),
|
||||
Salt: salt,
|
||||
Iterations: 4096,
|
||||
}.RawASN1(),
|
||||
},
|
||||
}
|
||||
p, _ := bmpString("sesame")
|
||||
|
||||
m, err := pbDecrypt(td, p)
|
||||
|
||||
switch e := expected[i].(type) {
|
||||
case []byte:
|
||||
if err != nil {
|
||||
t.Errorf("error decrypting C=%x: %v", c, err)
|
||||
}
|
||||
if !bytes.Equal(m, e) {
|
||||
t.Errorf("expected C=%x to be decoded to M=%x, but found %x", c, e, m)
|
||||
}
|
||||
case error:
|
||||
if err == nil || err.Error() != e.Error() {
|
||||
t.Errorf("expecting error '%v' during decryption of c=%x, but found err='%v'", e, c, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return decryptable
|
||||
}
|
||||
|
||||
type testDecryptable struct {
|
||||
|
@ -141,8 +152,8 @@ type testDecryptable struct {
|
|||
algorithm pkix.AlgorithmIdentifier
|
||||
}
|
||||
|
||||
func (d testDecryptable) GetAlgorithm() pkix.AlgorithmIdentifier { return d.algorithm }
|
||||
func (d testDecryptable) GetData() []byte { return d.data }
|
||||
func (d testDecryptable) Algorithm() pkix.AlgorithmIdentifier { return d.algorithm }
|
||||
func (d testDecryptable) Data() []byte { return d.data }
|
||||
|
||||
func (params pbeParams) RawASN1() (raw asn1.RawValue) {
|
||||
asn1Bytes, err := asn1.Marshal(params)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import "errors"
|
||||
|
@ -16,7 +20,7 @@ type NotImplementedError string
|
|||
type EncodeError string
|
||||
|
||||
func (e NotImplementedError) Error() string {
|
||||
return string(e)
|
||||
return "pkcs12: " + string(e)
|
||||
}
|
||||
|
||||
func (e EncodeError) Error() string {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
|
@ -7,10 +11,6 @@ import (
|
|||
"encoding/asn1"
|
||||
)
|
||||
|
||||
var (
|
||||
oidSha1Algorithm = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
|
||||
)
|
||||
|
||||
type macData struct {
|
||||
Mac digestInfo
|
||||
MacSalt []byte
|
||||
|
@ -23,6 +23,23 @@ type digestInfo struct {
|
|||
Digest []byte
|
||||
}
|
||||
|
||||
var (
|
||||
oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
|
||||
)
|
||||
|
||||
func verifyMac(macData *macData, message, password []byte) error {
|
||||
if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
|
||||
return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
|
||||
}
|
||||
|
||||
expectedMAC := computeMac(message, macData.Iterations, macData.MacSalt, password)
|
||||
|
||||
if !hmac.Equal(macData.Mac.Digest, expectedMAC) {
|
||||
return ErrIncorrectPassword
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func computeMac(message []byte, iterations int, salt, password []byte) []byte {
|
||||
key := pbkdf(sha1Sum, 20, 64, salt, password, iterations, 3, 20)
|
||||
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"encoding/asn1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func verifyMac(macData *macData, message, password []byte) error {
|
||||
if !macData.Mac.Algorithm.Algorithm.Equal(oidSha1Algorithm) {
|
||||
return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
|
||||
}
|
||||
|
||||
expectedMAC := computeMac(message, macData.Iterations, macData.MacSalt, password)
|
||||
|
||||
if !hmac.Equal(macData.Mac.Digest, expectedMAC) {
|
||||
return ErrIncorrectPassword
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestVerifyMac(t *testing.T) {
|
||||
td := macData{
|
||||
Mac: digestInfo{
|
||||
|
|
|
@ -1,34 +1,35 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var (
|
||||
deriveKeyByAlg = map[string]func(salt, password []byte, iterations int) []byte{
|
||||
pbeWithSHAAnd3KeyTripleDESCBC: func(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24)
|
||||
},
|
||||
pbewithSHAAnd40BitRC2CBC: func(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5)
|
||||
},
|
||||
}
|
||||
deriveIVByAlg = map[string]func(salt, password []byte, iterations int) []byte{
|
||||
pbeWithSHAAnd3KeyTripleDESCBC: func(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
|
||||
},
|
||||
pbewithSHAAnd40BitRC2CBC: func(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
|
||||
},
|
||||
}
|
||||
one = big.NewInt(1)
|
||||
)
|
||||
|
||||
// sha1Sum returns the SHA-1 hash of in.
|
||||
func sha1Sum(in []byte) []byte {
|
||||
sum := sha1.Sum(in)
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of
|
||||
// repeats of pattern.
|
||||
func fillWithRepeats(pattern []byte, v int) []byte {
|
||||
if len(pattern) == 0 {
|
||||
return nil
|
||||
}
|
||||
outputLen := v * ((len(pattern) + v - 1) / v)
|
||||
return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen]
|
||||
}
|
||||
|
||||
func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) {
|
||||
// implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments
|
||||
|
||||
|
@ -75,7 +76,7 @@ func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID
|
|||
|
||||
// 1. Construct a string, D (the "diversifier"), by concatenating v/8
|
||||
// copies of ID.
|
||||
D := []byte{}
|
||||
var D []byte
|
||||
for i := 0; i < v; i++ {
|
||||
D = append(D, ID)
|
||||
}
|
||||
|
@ -85,63 +86,37 @@ func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID
|
|||
// truncated to create S). Note that if the salt is the empty
|
||||
// string, then so is S.
|
||||
|
||||
S := []byte{}
|
||||
{
|
||||
s := len(salt)
|
||||
times := s / v
|
||||
if s%v > 0 {
|
||||
times++
|
||||
}
|
||||
for len(S) < times*v {
|
||||
S = append(S, salt...)
|
||||
}
|
||||
S = S[:times*v]
|
||||
}
|
||||
S := fillWithRepeats(salt, v)
|
||||
|
||||
// 3. Concatenate copies of the password together to create a string P
|
||||
// of length v(ceiling(p/v)) bits (the final copy of the password
|
||||
// may be truncated to create P). Note that if the password is the
|
||||
// empty string, then so is P.
|
||||
|
||||
P := []byte{}
|
||||
{
|
||||
s := len(password)
|
||||
times := s / v
|
||||
if s%v > 0 {
|
||||
times++
|
||||
}
|
||||
for len(P) < times*v {
|
||||
P = append(P, password...)
|
||||
}
|
||||
P = P[:times*v]
|
||||
}
|
||||
P := fillWithRepeats(password, v)
|
||||
|
||||
// 4. Set I=S||P to be the concatenation of S and P.
|
||||
I := append(S, P...)
|
||||
|
||||
// 5. Set c=ceiling(n/u).
|
||||
c := size / u
|
||||
if size%u > 0 {
|
||||
c++
|
||||
}
|
||||
c := (size + u - 1) / u
|
||||
|
||||
// 6. For i=1, 2, ..., c, do the following:
|
||||
A := make([]byte, c*20)
|
||||
var IjBuf []byte
|
||||
for i := 0; i < c; i++ {
|
||||
|
||||
// A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
|
||||
// H(H(H(... H(D||I))))
|
||||
Ai := hash(append(D, I...))
|
||||
for j := 1; j < r; j++ {
|
||||
Ai = hash(Ai[:])
|
||||
Ai = hash(Ai)
|
||||
}
|
||||
copy(A[i*20:], Ai[:])
|
||||
|
||||
if i < c-1 { // skip on last iteration
|
||||
|
||||
// B. Concatenate copies of Ai to create a string B of length v
|
||||
// bits (the final copy of Ai may be truncated to create B).
|
||||
B := []byte{}
|
||||
var B []byte
|
||||
for len(B) < v {
|
||||
B = append(B, Ai[:]...)
|
||||
}
|
||||
|
@ -151,20 +126,31 @@ func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID
|
|||
// blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
|
||||
// setting I_j=(I_j+B+1) mod 2^v for each j.
|
||||
{
|
||||
Bbi := new(big.Int)
|
||||
Bbi.SetBytes(B)
|
||||
|
||||
one := big.NewInt(1)
|
||||
Bbi := new(big.Int).SetBytes(B)
|
||||
Ij := new(big.Int)
|
||||
|
||||
for j := 0; j < len(I)/v; j++ {
|
||||
Ij := new(big.Int)
|
||||
Ij.SetBytes(I[j*v : (j+1)*v])
|
||||
Ij.Add(Ij, Bbi)
|
||||
Ij.Add(Ij, one)
|
||||
Ijb := Ij.Bytes()
|
||||
// We expect Ijb to be exactly v bytes,
|
||||
// if it is longer or shorter we must
|
||||
// adjust it accordingly.
|
||||
if len(Ijb) > v {
|
||||
Ijb = Ijb[len(Ijb)-v:]
|
||||
}
|
||||
if len(Ijb) < v {
|
||||
if IjBuf == nil {
|
||||
IjBuf = make([]byte, v)
|
||||
}
|
||||
bytesShort := v - len(Ijb)
|
||||
for i := 0; i < bytesShort; i++ {
|
||||
IjBuf[i] = 0
|
||||
}
|
||||
copy(IjBuf[bytesShort:], Ijb)
|
||||
Ijb = IjBuf
|
||||
}
|
||||
copy(I[j*v:(j+1)*v], Ijb)
|
||||
}
|
||||
}
|
||||
|
@ -174,9 +160,7 @@ func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID
|
|||
// bit string, A.
|
||||
|
||||
// 8. Use the first n bits of A as the output of this entire process.
|
||||
A = A[:size]
|
||||
|
||||
return A
|
||||
return A[:size]
|
||||
|
||||
// If the above process is being used to generate a DES key, the process
|
||||
// should be used to create 64 random bits, and the key's parity bits
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
|
@ -6,13 +10,25 @@ import (
|
|||
)
|
||||
|
||||
func TestThatPBKDFWorksCorrectlyForLongKeys(t *testing.T) {
|
||||
pbkdf := deriveKeyByAlg[pbeWithSHAAnd3KeyTripleDESCBC]
|
||||
cipherInfo := shaWithTripleDESCBC{}
|
||||
|
||||
salt := []byte("\xff\xff\xff\xff\xff\xff\xff\xff")
|
||||
password, _ := bmpString("sesame")
|
||||
key := pbkdf(salt, password, 2048)
|
||||
key := cipherInfo.deriveKey(salt, password, 2048)
|
||||
|
||||
if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); !bytes.Equal(key, expected) {
|
||||
t.Fatalf("expected key '% x', but found '% x'", key, expected)
|
||||
if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); bytes.Compare(key, expected) != 0 {
|
||||
t.Fatalf("expected key '%x', but found '%x'", expected, key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestThatPBKDFHandlesLeadingZeros(t *testing.T) {
|
||||
// This test triggers a case where I_j (in step 6C) ends up with leading zero
|
||||
// byte, meaning that len(Ijb) < v (leading zeros get stripped by big.Int).
|
||||
// This was previously causing bug whereby certain inputs would break the
|
||||
// derivation and produce the wrong output.
|
||||
key := pbkdf(sha1Sum, 20, 64, []byte("\xf3\x7e\x05\xb5\x18\x32\x4b\x4b"), []byte("\x00\x00"), 2048, 1, 24)
|
||||
expected := []byte("\x00\xf7\x59\xff\x47\xd1\x4d\xd0\x36\x65\xd5\x94\x3c\xb3\xc4\xa3\x9a\x25\x55\xc0\x2a\xed\x66\xe1")
|
||||
if bytes.Compare(key, expected) != 0 {
|
||||
t.Fatalf("expected key '%x', but found '%x'", expected, key)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,34 @@
|
|||
// Package pkcs12 provides some implementations of PKCS#12.
|
||||
// Copyright 2015 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 pkcs12 implements some of PKCS#12.
|
||||
//
|
||||
// This implementation is distilled from https://tools.ietf.org/html/rfc7292 and referenced documents.
|
||||
// It is intended for decoding P12/PFX-stored certificate+key for use with the crypto/tls package.
|
||||
// This implementation is distilled from https://tools.ietf.org/html/rfc7292
|
||||
// and referenced documents. It is intended for decoding P12/PFX-stored
|
||||
// certificates and keys for use with the crypto/tls package.
|
||||
package pkcs12
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
oidLocalKeyID = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 21}
|
||||
oidDataContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
|
||||
oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
|
||||
oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
|
||||
|
||||
oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
|
||||
oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
|
||||
oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
|
||||
|
||||
localKeyId = []byte{0x01, 0x00, 0x00, 0x00}
|
||||
)
|
||||
|
@ -30,6 +44,23 @@ type contentInfo struct {
|
|||
Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
|
||||
}
|
||||
|
||||
type encryptedData struct {
|
||||
Version int
|
||||
EncryptedContentInfo encryptedContentInfo
|
||||
}
|
||||
|
||||
type encryptedContentInfo struct {
|
||||
ContentType asn1.ObjectIdentifier
|
||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedContent []byte `asn1:"tag:0,optional"`
|
||||
}
|
||||
|
||||
func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
|
||||
return i.ContentEncryptionAlgorithm
|
||||
}
|
||||
|
||||
func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
|
||||
|
||||
type safeBag struct {
|
||||
Id asn1.ObjectIdentifier
|
||||
Value asn1.RawValue `asn1:"tag:0,explicit"`
|
||||
|
@ -38,7 +69,7 @@ type safeBag struct {
|
|||
|
||||
type pkcs12Attribute struct {
|
||||
Id asn1.ObjectIdentifier
|
||||
Value asn1.RawValue `ans1:"set"`
|
||||
Value asn1.RawValue `asn1:"set"`
|
||||
}
|
||||
|
||||
type encryptedPrivateKeyInfo struct {
|
||||
|
@ -46,8 +77,19 @@ type encryptedPrivateKeyInfo struct {
|
|||
EncryptedData []byte
|
||||
}
|
||||
|
||||
func (i encryptedPrivateKeyInfo) GetAlgorithm() pkix.AlgorithmIdentifier { return i.AlgorithmIdentifier }
|
||||
func (i encryptedPrivateKeyInfo) GetData() []byte { return i.EncryptedData }
|
||||
func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
|
||||
return i.AlgorithmIdentifier
|
||||
}
|
||||
|
||||
func (i encryptedPrivateKeyInfo) Data() []byte {
|
||||
return i.EncryptedData
|
||||
}
|
||||
|
||||
// PEM block types
|
||||
const (
|
||||
certificateType = "CERTIFICATE"
|
||||
privateKeyType = "PRIVATE KEY"
|
||||
)
|
||||
|
||||
// unmarshal calls asn1.Unmarshal, but also returns an error if there is any
|
||||
// trailing data after unmarshaling.
|
||||
|
@ -62,6 +104,168 @@ func unmarshal(in []byte, out interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks.
|
||||
func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
|
||||
encodedPassword, err := bmpString(password)
|
||||
if err != nil {
|
||||
return nil, ErrIncorrectPassword
|
||||
}
|
||||
|
||||
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
|
||||
|
||||
blocks := make([]*pem.Block, 0, len(bags))
|
||||
for _, bag := range bags {
|
||||
block, err := convertBag(&bag, encodedPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
|
||||
block := &pem.Block{
|
||||
Headers: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, attribute := range bag.Attributes {
|
||||
k, v, err := convertAttribute(&attribute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block.Headers[k] = v
|
||||
}
|
||||
|
||||
switch {
|
||||
case bag.Id.Equal(oidCertBag):
|
||||
block.Type = certificateType
|
||||
certsData, err := decodeCertBag(bag.Value.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block.Bytes = certsData
|
||||
case bag.Id.Equal(oidPKCS8ShroudedKeyBag):
|
||||
block.Type = privateKeyType
|
||||
|
||||
key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch key := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
block.Bytes = x509.MarshalPKCS1PrivateKey(key)
|
||||
case *ecdsa.PrivateKey:
|
||||
block.Bytes, err = x509.MarshalECPrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
|
||||
isString := false
|
||||
|
||||
switch {
|
||||
case attribute.Id.Equal(oidFriendlyName):
|
||||
key = "friendlyName"
|
||||
isString = true
|
||||
case attribute.Id.Equal(oidLocalKeyID):
|
||||
key = "localKeyId"
|
||||
case attribute.Id.Equal(oidMicrosoftCSPName):
|
||||
// This key is chosen to match OpenSSL.
|
||||
key = "Microsoft CSP Name"
|
||||
isString = true
|
||||
default:
|
||||
return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
|
||||
}
|
||||
|
||||
if isString {
|
||||
if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
} else {
|
||||
var id []byte
|
||||
if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
value = hex.EncodeToString(id)
|
||||
}
|
||||
|
||||
return key, value, nil
|
||||
}
|
||||
|
||||
// Decode extracts a certificate and private key from pfxData. This function
|
||||
// assumes that there is only one certificate and only one private key in the
|
||||
// pfxData.
|
||||
func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
|
||||
encodedPassword, err := bmpString(password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(bags) != 2 {
|
||||
err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
|
||||
return
|
||||
}
|
||||
|
||||
for _, bag := range bags {
|
||||
switch {
|
||||
case bag.Id.Equal(oidCertBag):
|
||||
if certificate != nil {
|
||||
err = errors.New("pkcs12: expected exactly one certificate bag")
|
||||
}
|
||||
|
||||
certsData, err := decodeCertBag(bag.Value.Bytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
certs, err := x509.ParseCertificates(certsData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(certs) != 1 {
|
||||
err = errors.New("pkcs12: expected exactly one certificate in the certBag")
|
||||
return nil, nil, err
|
||||
}
|
||||
certificate = certs[0]
|
||||
|
||||
case bag.Id.Equal(oidPKCS8ShroudedKeyBag):
|
||||
if privateKey != nil {
|
||||
err = errors.New("pkcs12: expected exactly one key bag")
|
||||
}
|
||||
if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if certificate == nil {
|
||||
return nil, nil, errors.New("pkcs12: certificate missing")
|
||||
}
|
||||
if privateKey == nil {
|
||||
return nil, nil, errors.New("pkcs12: private key missing")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getLocalKeyId(id []byte) (attribute pkcs12Attribute, err error) {
|
||||
octetString := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: id}
|
||||
bytes, err := asn1.Marshal(octetString)
|
||||
|
@ -115,7 +319,7 @@ func makeCertBagContentInfo(derBytes []byte) (*contentInfo, error) {
|
|||
return nil, EncodeError("encoding cert bag: " + err.Error())
|
||||
}
|
||||
|
||||
certSafeBags, err := makeSafeBags(oidCertBagType, bytes)
|
||||
certSafeBags, err := makeSafeBags(oidCertBag, bytes)
|
||||
if err != nil {
|
||||
return nil, EncodeError("safe bags: " + err.Error())
|
||||
}
|
||||
|
@ -129,7 +333,7 @@ func makeShroudedKeyBagContentInfo(privateKey interface{}, password []byte) (*co
|
|||
return nil, EncodeError("encode PKCS#8 shrouded key bag: " + err.Error())
|
||||
}
|
||||
|
||||
safeBags, err := makeSafeBags(oidPkcs8ShroudedKeyBagType, shroudedKeyBagBytes)
|
||||
safeBags, err := makeSafeBags(oidPKCS8ShroudedKeyBag, shroudedKeyBagBytes)
|
||||
if err != nil {
|
||||
return nil, EncodeError("safe bags: " + err.Error())
|
||||
}
|
||||
|
@ -183,7 +387,7 @@ func makeSalt(saltByteCount int) ([]byte, error) {
|
|||
//
|
||||
// derBytes is a DER encoded certificate.
|
||||
// privateKey is an RSA
|
||||
func Encode(derBytes []byte, privateKey interface{}, password string) ([]byte, error) {
|
||||
func Encode(derBytes []byte, privateKey interface{}, password string) (pfxBytes []byte, err error) {
|
||||
secret, err := bmpString(password)
|
||||
if err != nil {
|
||||
return nil, ErrIncorrectPassword
|
||||
|
@ -230,7 +434,7 @@ func Encode(derBytes []byte, privateKey interface{}, password string) ([]byte, e
|
|||
MacSalt: salt,
|
||||
Mac: digestInfo{
|
||||
Algorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: oidSha1Algorithm,
|
||||
Algorithm: oidSHA1,
|
||||
},
|
||||
Digest: digest,
|
||||
},
|
||||
|
@ -244,3 +448,83 @@ func Encode(derBytes []byte, privateKey interface{}, password string) ([]byte, e
|
|||
|
||||
return bytes, err
|
||||
}
|
||||
|
||||
func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
|
||||
pfx := new(pfxPdu)
|
||||
|
||||
if err := unmarshal(p12Data, pfx); err != nil {
|
||||
return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
|
||||
}
|
||||
|
||||
if pfx.Version != 3 {
|
||||
return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
|
||||
}
|
||||
|
||||
if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
|
||||
return nil, nil, NotImplementedError("only password-protected PFX is implemented")
|
||||
}
|
||||
|
||||
// unmarshal the explicit bytes in the content for type 'data'
|
||||
if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
|
||||
return nil, nil, errors.New("pkcs12: no MAC in data")
|
||||
}
|
||||
|
||||
if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
|
||||
if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
|
||||
// some implementations use an empty byte array
|
||||
// for the empty string password try one more
|
||||
// time with empty-empty password
|
||||
password = nil
|
||||
err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var authenticatedSafe []contentInfo
|
||||
if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(authenticatedSafe) != 2 {
|
||||
return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
|
||||
}
|
||||
|
||||
for _, ci := range authenticatedSafe {
|
||||
var data []byte
|
||||
|
||||
switch {
|
||||
case ci.ContentType.Equal(oidDataContentType):
|
||||
if err := unmarshal(ci.Content.Bytes, &data); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
case ci.ContentType.Equal(oidEncryptedDataContentType):
|
||||
var encryptedData encryptedData
|
||||
if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if encryptedData.Version != 0 {
|
||||
return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
|
||||
}
|
||||
if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
default:
|
||||
return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
|
||||
}
|
||||
|
||||
var safeContents []safeBag
|
||||
if err := unmarshal(data, &safeContents); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
bags = append(bags, safeContents...)
|
||||
}
|
||||
|
||||
return bags, password, nil
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
|
@ -5,16 +9,36 @@ import (
|
|||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
gopkcs12 "golang.org/x/crypto/pkcs12"
|
||||
)
|
||||
|
||||
func TestPfx(t *testing.T) {
|
||||
for commonName, base64P12 := range testdata {
|
||||
p12, _ := base64.StdEncoding.DecodeString(base64P12)
|
||||
|
||||
priv, cert, err := Decode(p12, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := priv.(*rsa.PrivateKey).Validate(); err != nil {
|
||||
t.Errorf("error while validating private key: %v", err)
|
||||
}
|
||||
|
||||
if cert.Subject.CommonName != commonName {
|
||||
t.Errorf("expected common name to be %q, but found %q", commonName, cert.Subject.CommonName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPfxRoundTriRsa(t *testing.T) {
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 512)
|
||||
if err != nil {
|
||||
|
@ -25,7 +49,7 @@ func TestPfxRoundTriRsa(t *testing.T) {
|
|||
|
||||
actualPrivateKey, ok := key.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
t.Fatal("failed to decode private key")
|
||||
t.Fatalf("failed to decode private key")
|
||||
}
|
||||
|
||||
if privateKey.D.Cmp(actualPrivateKey.D) != 0 {
|
||||
|
@ -62,7 +86,7 @@ func testPfxRoundTrip(t *testing.T, privateKey interface{}) interface{} {
|
|||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
key, _, err := gopkcs12.Decode(bytes, "sesame")
|
||||
key, _, err := Decode(bytes, "sesame")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
@ -70,6 +94,61 @@ func testPfxRoundTrip(t *testing.T, privateKey interface{}) interface{} {
|
|||
return key
|
||||
}
|
||||
|
||||
func TestPEM(t *testing.T) {
|
||||
for commonName, base64P12 := range testdata {
|
||||
p12, _ := base64.StdEncoding.DecodeString(base64P12)
|
||||
|
||||
blocks, err := ToPEM(p12, "")
|
||||
if err != nil {
|
||||
t.Fatalf("error while converting to PEM: %s", err)
|
||||
}
|
||||
|
||||
var pemData []byte
|
||||
for _, b := range blocks {
|
||||
pemData = append(pemData, pem.EncodeToMemory(b)...)
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair(pemData, pemData)
|
||||
if err != nil {
|
||||
t.Errorf("err while converting to key pair: %v", err)
|
||||
}
|
||||
config := tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
config.BuildNameToCertificate()
|
||||
|
||||
if _, exists := config.NameToCertificate[commonName]; !exists {
|
||||
t.Errorf("did not find our cert in PEM?: %v", config.NameToCertificate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleToPEM() {
|
||||
p12, _ := base64.StdEncoding.DecodeString(`MIIJzgIBAzCCCZQGCS ... CA+gwggPk==`)
|
||||
|
||||
blocks, err := ToPEM(p12, "password")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var pemData []byte
|
||||
for _, b := range blocks {
|
||||
pemData = append(pemData, pem.EncodeToMemory(b)...)
|
||||
}
|
||||
|
||||
// then use PEM data for tls to construct tls certificate:
|
||||
cert, err := tls.X509KeyPair(pemData, pemData)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
|
||||
_ = config
|
||||
}
|
||||
|
||||
func newCertificate(hostname string, privateKey interface{}) ([]byte, error) {
|
||||
t, _ := time.Parse("2006-01-02", "2016-01-01")
|
||||
notBefore := t
|
||||
|
@ -115,3 +194,54 @@ func newCertificate(hostname string, privateKey interface{}) ([]byte, error) {
|
|||
|
||||
return derBytes, nil
|
||||
}
|
||||
|
||||
var testdata = map[string]string{
|
||||
// 'null' password test case
|
||||
"Windows Azure Tools": `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`,
|
||||
// empty string password test case
|
||||
"testing@example.com": `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
|
||||
HQ8CAggA`,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright 2016 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 pkcs12
|
||||
|
||||
import (
|
||||
|
@ -28,7 +31,7 @@ var (
|
|||
|
||||
// marshalPKCS8PrivateKey converts a private key to PKCS#8 encoded form.
|
||||
// See http://www.rsa.com/rsalabs/node.asp?id=2130 and RFC5208.
|
||||
func marshalPKCS8PrivateKey(key interface{}) ([]byte, error) {
|
||||
func marshalPKCS8PrivateKey(key interface{}) (der []byte, err error) {
|
||||
pkcs := pkcs8{
|
||||
Version: 0,
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ func TestRoundTripPkcs8Rsa(t *testing.T) {
|
|||
}
|
||||
|
||||
if actualPrivateKey.Validate() != nil {
|
||||
t.Fatal("private key did not validate")
|
||||
t.Fatalf("private key did not validate")
|
||||
}
|
||||
|
||||
if actualPrivateKey.N.Cmp(privateKey.N) != 0 {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2015 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 rc2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkEncrypt(b *testing.B) {
|
||||
r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64)
|
||||
b.ResetTimer()
|
||||
var src [8]byte
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Encrypt(src[:], src[:])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecrypt(b *testing.B) {
|
||||
r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64)
|
||||
b.ResetTimer()
|
||||
var src [8]byte
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Decrypt(src[:], src[:])
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2015 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 rc2 implements the RC2 cipher
|
||||
/*
|
||||
https://www.ietf.org/rfc/rfc2268.txt
|
||||
|
@ -10,7 +14,6 @@ package rc2
|
|||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// The rc2 block size in bytes
|
||||
|
@ -20,34 +23,15 @@ type rc2Cipher struct {
|
|||
k [64]uint16
|
||||
}
|
||||
|
||||
// KeySizeError indicates the supplied key was invalid
|
||||
type KeySizeError int
|
||||
|
||||
func (k KeySizeError) Error() string { return "rc2: invalid key size " + strconv.Itoa(int(k)) }
|
||||
|
||||
// EffectiveKeySizeError indicates the supplied effective key length was invalid
|
||||
type EffectiveKeySizeError int
|
||||
|
||||
func (k EffectiveKeySizeError) Error() string {
|
||||
return "rc2: invalid effective key size " + strconv.Itoa(int(k))
|
||||
}
|
||||
|
||||
// New returns a new rc2 cipher with the given key and effective key length t1
|
||||
func New(key []byte, t1 int) (cipher.Block, error) {
|
||||
if l := len(key); l == 0 || l > 128 {
|
||||
return nil, KeySizeError(l)
|
||||
}
|
||||
|
||||
if t1 < 8 || t1 > 1024 {
|
||||
return nil, EffectiveKeySizeError(t1)
|
||||
}
|
||||
|
||||
// TODO(dgryski): error checking for key length
|
||||
return &rc2Cipher{
|
||||
k: expandKey(key, t1),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *rc2Cipher) BlockSize() int { return BlockSize }
|
||||
func (*rc2Cipher) BlockSize() int { return BlockSize }
|
||||
|
||||
var piTable = [256]byte{
|
||||
0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
|
||||
|
@ -109,7 +93,6 @@ func (c *rc2Cipher) Encrypt(dst, src []byte) {
|
|||
|
||||
var j int
|
||||
|
||||
// These three mix blocks have not been extracted to a common function for to performance reasons.
|
||||
for j <= 16 {
|
||||
// mix r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
|
@ -130,6 +113,7 @@ func (c *rc2Cipher) Encrypt(dst, src []byte) {
|
|||
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
|
||||
r3 = rotl16(r3, 5)
|
||||
j++
|
||||
|
||||
}
|
||||
|
||||
r0 = r0 + c.k[r3&63]
|
||||
|
@ -138,6 +122,7 @@ func (c *rc2Cipher) Encrypt(dst, src []byte) {
|
|||
r3 = r3 + c.k[r2&63]
|
||||
|
||||
for j <= 40 {
|
||||
|
||||
// mix r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
r0 = rotl16(r0, 1)
|
||||
|
@ -157,6 +142,7 @@ func (c *rc2Cipher) Encrypt(dst, src []byte) {
|
|||
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
|
||||
r3 = rotl16(r3, 5)
|
||||
j++
|
||||
|
||||
}
|
||||
|
||||
r0 = r0 + c.k[r3&63]
|
||||
|
@ -165,6 +151,7 @@ func (c *rc2Cipher) Encrypt(dst, src []byte) {
|
|||
r3 = r3 + c.k[r2&63]
|
||||
|
||||
for j <= 60 {
|
||||
|
||||
// mix r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
r0 = rotl16(r0, 1)
|
||||
|
@ -248,6 +235,7 @@ func (c *rc2Cipher) Decrypt(dst, src []byte) {
|
|||
r0 = rotl16(r0, 16-1)
|
||||
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
|
||||
j--
|
||||
|
||||
}
|
||||
|
||||
r3 = r3 - c.k[r2&63]
|
||||
|
@ -256,6 +244,7 @@ func (c *rc2Cipher) Decrypt(dst, src []byte) {
|
|||
r0 = r0 - c.k[r3&63]
|
||||
|
||||
for j >= 0 {
|
||||
|
||||
// unmix r3
|
||||
r3 = rotl16(r3, 16-5)
|
||||
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
|
||||
|
@ -275,6 +264,7 @@ func (c *rc2Cipher) Decrypt(dst, src []byte) {
|
|||
r0 = rotl16(r0, 16-1)
|
||||
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
|
||||
j--
|
||||
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint16(dst[0:], r0)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2015 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 rc2
|
||||
|
||||
import (
|
||||
|
@ -8,6 +12,7 @@ import (
|
|||
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
|
||||
// TODO(dgryski): add the rest of the test vectors from the RFC
|
||||
var tests = []struct {
|
||||
key string
|
||||
plain string
|
||||
|
@ -86,20 +91,3 @@ func TestEncryptDecrypt(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncrypt(b *testing.B) {
|
||||
r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64)
|
||||
b.ResetTimer()
|
||||
var src [8]byte
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Encrypt(src[:], src[:])
|
||||
}
|
||||
}
|
||||
func BenchmarkDecrypt(b *testing.B) {
|
||||
r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64)
|
||||
b.ResetTimer()
|
||||
var src [8]byte
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Decrypt(src[:], src[:])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
// Copyright 2015 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 pkcs12
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
)
|
||||
|
||||
//see https://tools.ietf.org/html/rfc7292#appendix-D
|
||||
var (
|
||||
oidPkcs8ShroudedKeyBagType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 12, 10, 1, 2}
|
||||
oidCertBagType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 12, 10, 1, 3}
|
||||
|
||||
oidCertTypeX509Certificate = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 22, 1}
|
||||
// see https://tools.ietf.org/html/rfc7292#appendix-D
|
||||
oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1})
|
||||
oidPKCS8ShroudedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2})
|
||||
oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3})
|
||||
)
|
||||
|
||||
type certBag struct {
|
||||
|
@ -52,7 +56,7 @@ func encodePkcs8ShroudedKeyBag(privateKey interface{}, password []byte) (bytes [
|
|||
|
||||
pkinfo := encryptedPrivateKeyInfo{
|
||||
AlgorithmIdentifier: pkix.AlgorithmIdentifier{
|
||||
Algorithm: oidPbeWithSHAAnd3KeyTripleDESCBC,
|
||||
Algorithm: oidPBEWithSHAAnd3KeyTripleDESCBC,
|
||||
Parameters: params,
|
||||
},
|
||||
EncryptedData: pkData,
|
||||
|
@ -65,3 +69,37 @@ func encodePkcs8ShroudedKeyBag(privateKey interface{}, password []byte) (bytes [
|
|||
|
||||
return bytes, err
|
||||
}
|
||||
|
||||
func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) {
|
||||
pkinfo := new(encryptedPrivateKeyInfo)
|
||||
if err = unmarshal(asn1Data, pkinfo); err != nil {
|
||||
return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error())
|
||||
}
|
||||
|
||||
pkData, err := pbDecrypt(pkinfo, password)
|
||||
if err != nil {
|
||||
return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error())
|
||||
}
|
||||
|
||||
ret := new(asn1.RawValue)
|
||||
if err = unmarshal(pkData, ret); err != nil {
|
||||
return nil, errors.New("pkcs12: error unmarshaling decrypted private key: " + err.Error())
|
||||
}
|
||||
|
||||
if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil {
|
||||
return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error())
|
||||
}
|
||||
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) {
|
||||
bag := new(certBag)
|
||||
if err := unmarshal(asn1Data, bag); err != nil {
|
||||
return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error())
|
||||
}
|
||||
if !bag.Id.Equal(oidCertTypeX509Certificate) {
|
||||
return nil, NotImplementedError("only X509 certificates are supported")
|
||||
}
|
||||
return bag.Data, nil
|
||||
}
|
||||
|
|
|
@ -1,39 +1,15 @@
|
|||
// Copyright 2016 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 pkcs12
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) {
|
||||
pkinfo := new(encryptedPrivateKeyInfo)
|
||||
if _, err = asn1.Unmarshal(asn1Data, pkinfo); err != nil {
|
||||
err = fmt.Errorf("error decoding PKCS8 shrouded key bag: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkData, err := pbDecrypt(pkinfo, password)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error decrypting PKCS8 shrouded key bag: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
rv := new(asn1.RawValue)
|
||||
if _, err = asn1.Unmarshal(pkData, rv); err != nil {
|
||||
err = fmt.Errorf("could not decode decrypted private key data")
|
||||
}
|
||||
|
||||
if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil {
|
||||
err = fmt.Errorf("error parsing PKCS8 private key: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Assert the default algorithm parameters are in the correct order,
|
||||
// and default to the correct value. Defaults are based on OpenSSL.
|
||||
// 1. IterationCount, defaults to 2,048 long.
|
||||
|
@ -61,7 +37,7 @@ func TestDefaultAlgorithmParametersPkcs8ShroudedKeyBag(t *testing.T) {
|
|||
}
|
||||
|
||||
var params pbeParams
|
||||
rest, err = asn1.Unmarshal(pkinfo.GetAlgorithm().Parameters.FullBytes, ¶ms)
|
||||
rest, err = asn1.Unmarshal(pkinfo.Algorithm().Parameters.FullBytes, ¶ms)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal encryptedPrivateKeyInfo %s", err)
|
||||
}
|
||||
|
@ -97,6 +73,6 @@ func TestRoundTripPkcs8ShroudedKeyBag(t *testing.T) {
|
|||
|
||||
actualPrivateKey := key.(*rsa.PrivateKey)
|
||||
if actualPrivateKey.D.Cmp(privateKey.D) != 0 {
|
||||
t.Fatal("failed to round-trip rsa.PrivateKey.D")
|
||||
t.Fatalf("failed to round-trip rsa.PrivateKey.D")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue