mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-22 10:16:18 +08:00
pkcs8: support legacy PBES1 algorithms (parse only)
This commit is contained in:
parent
ff1269c9dc
commit
41f4ec0e83
158
pkcs/internal/md2/md2.go
Normal file
158
pkcs/internal/md2/md2.go
Normal file
@ -0,0 +1,158 @@
|
||||
// Package md2 implements the MD2 hash algorithm as defined in RFC 1319.
|
||||
//
|
||||
// MD2 is cryptographically broken and should not be used for secure
|
||||
// applications.
|
||||
package md2
|
||||
|
||||
import "hash"
|
||||
|
||||
// Size the size of a MD2 checksum in bytes.
|
||||
const Size int = 16
|
||||
|
||||
// SizeBitSize the bit size of Size.
|
||||
const SizeBitSize = 4
|
||||
|
||||
// BlockSize the blocksize of MD2 in bytes.
|
||||
const BlockSize int = 16
|
||||
|
||||
var piSubst = [256]byte{
|
||||
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
|
||||
0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
|
||||
0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
|
||||
0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
|
||||
0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
|
||||
0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
|
||||
0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
|
||||
0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
|
||||
0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
|
||||
0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
|
||||
0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
|
||||
0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
|
||||
0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
|
||||
0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
|
||||
0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
|
||||
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14,
|
||||
}
|
||||
|
||||
// digest represents the partial evaluation of a checksum.
|
||||
type digest struct {
|
||||
s [Size]byte // state
|
||||
c [BlockSize]byte // checksum
|
||||
x [BlockSize]byte // buffer
|
||||
nx int
|
||||
len uint64
|
||||
}
|
||||
|
||||
func (d *digest) Reset() {
|
||||
for i := range d.s {
|
||||
d.s[i] = 0
|
||||
}
|
||||
for i := range d.c {
|
||||
d.c[i] = 0
|
||||
}
|
||||
d.nx = 0
|
||||
d.len = 0
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash computing the MD2 checksum.
|
||||
func New() hash.Hash {
|
||||
d := new(digest)
|
||||
d.Reset()
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *digest) Size() int { return Size }
|
||||
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Write(p []byte) (nn int, err error) {
|
||||
nn = len(p)
|
||||
d.len += uint64(nn)
|
||||
if d.nx > 0 {
|
||||
n := copy(d.x[d.nx:], p)
|
||||
d.nx += n
|
||||
if d.nx == BlockSize {
|
||||
block(d, d.x[:])
|
||||
d.nx = 0
|
||||
}
|
||||
p = p[n:]
|
||||
}
|
||||
if len(p) >= BlockSize {
|
||||
n := len(p) &^ (BlockSize - 1)
|
||||
block(d, p[:n])
|
||||
p = p[n:]
|
||||
}
|
||||
if len(p) > 0 {
|
||||
d.nx = copy(d.x[:], p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
// Make a copy of d so that caller can keep writing and summing.
|
||||
d0 := *d
|
||||
hash := d0.checkSum()
|
||||
return append(in, hash[:]...)
|
||||
}
|
||||
|
||||
func (d *digest) checkSum() [Size]byte {
|
||||
// Pad out to multiple of BlockSize bytes.
|
||||
var tmp [BlockSize]byte
|
||||
padLen := BlockSize - d.nx
|
||||
for i := 0; i < padLen; i++ {
|
||||
tmp[i] = byte(padLen)
|
||||
}
|
||||
d.Write(tmp[:padLen])
|
||||
// The previous write ensures that a whole number of
|
||||
// blocks (i.e. a multiple of 16 bytes) have been hashed.
|
||||
if d.nx != 0 {
|
||||
panic("d.nx != 0")
|
||||
}
|
||||
|
||||
// Append the checksum
|
||||
d.Write(d.c[:])
|
||||
|
||||
var digest [Size]byte
|
||||
copy(digest[:], d.s[:])
|
||||
return digest
|
||||
}
|
||||
|
||||
func block(dig *digest, p []byte) {
|
||||
var X [48]byte
|
||||
for i := 0; i <= len(p)-BlockSize; i += BlockSize {
|
||||
// Form encryption block from state, block, and state ^ block.
|
||||
copy(X[:16], dig.s[:])
|
||||
copy(X[16:32], p[i:i+BlockSize])
|
||||
for j := 0; j < BlockSize; j++ {
|
||||
X[32+j] = X[16+j] ^ X[j]
|
||||
}
|
||||
|
||||
// Encrypt block (18 rounds)
|
||||
t := byte(0)
|
||||
for j := 0; j < 18; j++ {
|
||||
for k := 0; k < 48; k++ {
|
||||
X[k] ^= piSubst[t]
|
||||
t = X[k]
|
||||
}
|
||||
t = t + byte(j)
|
||||
}
|
||||
|
||||
// Save state
|
||||
copy(dig.s[:], X[:16])
|
||||
|
||||
// Update checksum
|
||||
t = dig.c[15]
|
||||
for j := 0; j < 16; j++ {
|
||||
dig.c[j] ^= piSubst[p[i+j]^t]
|
||||
t = dig.c[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sum returns the MD2 checksum of the data.
|
||||
func Sum(data []byte) [Size]byte {
|
||||
var d digest
|
||||
d.Reset()
|
||||
d.Write(data)
|
||||
return d.checkSum()
|
||||
}
|
32
pkcs/internal/md2/md2_test.go
Normal file
32
pkcs/internal/md2/md2_test.go
Normal file
@ -0,0 +1,32 @@
|
||||
package md2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type md2Test struct {
|
||||
out string
|
||||
in string
|
||||
}
|
||||
|
||||
var golden = []md2Test{
|
||||
{"8350e5a3e24c153df2275c9f80692773", ""},
|
||||
{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"},
|
||||
{"da853b0d3f88d99b30283a69e6ded6bb", "abc"},
|
||||
{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"},
|
||||
{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"},
|
||||
{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
|
||||
{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
|
||||
}
|
||||
|
||||
func TestGolden(t *testing.T) {
|
||||
for i := 0; i < len(golden); i++ {
|
||||
g := golden[i]
|
||||
h := Sum([]byte(g.in))
|
||||
s := fmt.Sprintf("%x", h)
|
||||
if s != g.out {
|
||||
t.Fatalf("MD2 function: md2(%s) = %s want %s", g.in, s, g.out)
|
||||
}
|
||||
}
|
||||
}
|
308
pkcs/internal/rc2/rc2.go
Normal file
308
pkcs/internal/rc2/rc2.go
Normal file
@ -0,0 +1,308 @@
|
||||
// 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
|
||||
http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf
|
||||
|
||||
This code is licensed under the MIT license.
|
||||
*/
|
||||
package rc2
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/emmansun/gmsm/internal/alias"
|
||||
)
|
||||
|
||||
// The rc2 block size in bytes
|
||||
const BlockSize = 8
|
||||
|
||||
type rc2Cipher struct {
|
||||
k [64]uint16
|
||||
}
|
||||
|
||||
// NewCipherWithEffectiveKeyBits returns a new rc2 cipher with the given key and effective key length in bits t1
|
||||
func NewCipherWithEffectiveKeyBits(key []byte, t1 int) (cipher.Block, error) {
|
||||
kLen := len(key)
|
||||
if kLen < 1 || kLen > 128 {
|
||||
return nil, fmt.Errorf("rc2: invalid key size %d", kLen)
|
||||
}
|
||||
if t1 < 1 || t1 > 1024 {
|
||||
return nil, fmt.Errorf("rc2: invalid effective key length %d", t1)
|
||||
}
|
||||
return &rc2Cipher{
|
||||
k: expandKey(key, t1),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewCipher returns a new rc2 cipher with the given key
|
||||
func NewCipher(key []byte) (cipher.Block, error) {
|
||||
return NewCipherWithEffectiveKeyBits(key, len(key)*8)
|
||||
}
|
||||
|
||||
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,
|
||||
0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
|
||||
0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
|
||||
0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
|
||||
0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
|
||||
0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
|
||||
0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
|
||||
0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
|
||||
0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
|
||||
0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
|
||||
0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
|
||||
0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
|
||||
0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
|
||||
0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
|
||||
0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
|
||||
0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad,
|
||||
}
|
||||
|
||||
func expandKey(key []byte, t1 int) [64]uint16 {
|
||||
l := make([]byte, 128)
|
||||
copy(l, key)
|
||||
|
||||
var t = len(key)
|
||||
var t8 = (t1 + 7) / 8 // effective key length in bytes
|
||||
var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8)))) // mask for the t1 rightmost bits of the last byte
|
||||
|
||||
for i := t; i < 128; i++ {
|
||||
l[i] = piTable[l[i-1]+l[i-t]]
|
||||
}
|
||||
|
||||
l[128-t8] = piTable[l[128-t8]&tm]
|
||||
|
||||
for i := 127 - t8; i >= 0; i-- {
|
||||
l[i] = piTable[l[i+1]^l[i+t8]]
|
||||
}
|
||||
|
||||
var k [64]uint16
|
||||
|
||||
for i := range k {
|
||||
k[i] = uint16(l[2*i]) | uint16(l[2*i+1])<<8
|
||||
}
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
// rotl16 rotates x left by b bits
|
||||
func rotl16(x uint16, b uint) uint16 {
|
||||
return (x >> (16 - b)) | (x << b)
|
||||
}
|
||||
|
||||
func (c *rc2Cipher) Encrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("rc2: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("rc2: output not full block")
|
||||
}
|
||||
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("rc2: invalid buffer overlap")
|
||||
}
|
||||
|
||||
r0 := binary.LittleEndian.Uint16(src[0:2])
|
||||
r1 := binary.LittleEndian.Uint16(src[2:4])
|
||||
r2 := binary.LittleEndian.Uint16(src[4:6])
|
||||
r3 := binary.LittleEndian.Uint16(src[6:BlockSize])
|
||||
|
||||
var j int
|
||||
|
||||
// perform 5 mixing rounds
|
||||
for j <= 16 {
|
||||
// mix up r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
r0 = rotl16(r0, 1)
|
||||
j++
|
||||
|
||||
// mix up r1
|
||||
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
|
||||
r1 = rotl16(r1, 2)
|
||||
j++
|
||||
|
||||
// mix up r2
|
||||
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
|
||||
r2 = rotl16(r2, 3)
|
||||
j++
|
||||
|
||||
// mix up r3
|
||||
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
|
||||
r3 = rotl16(r3, 5)
|
||||
j++
|
||||
}
|
||||
|
||||
// perform 1 mashing round
|
||||
r0 = r0 + c.k[r3&63]
|
||||
r1 = r1 + c.k[r0&63]
|
||||
r2 = r2 + c.k[r1&63]
|
||||
r3 = r3 + c.k[r2&63]
|
||||
|
||||
// perform 6 mixing rounds
|
||||
for j <= 40 {
|
||||
// mix up r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
r0 = rotl16(r0, 1)
|
||||
j++
|
||||
|
||||
// mix up r1
|
||||
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
|
||||
r1 = rotl16(r1, 2)
|
||||
j++
|
||||
|
||||
// mix up r2
|
||||
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
|
||||
r2 = rotl16(r2, 3)
|
||||
j++
|
||||
|
||||
// mix up r3
|
||||
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
|
||||
r3 = rotl16(r3, 5)
|
||||
j++
|
||||
}
|
||||
|
||||
// perform 1 mashing round
|
||||
r0 = r0 + c.k[r3&63]
|
||||
r1 = r1 + c.k[r0&63]
|
||||
r2 = r2 + c.k[r1&63]
|
||||
r3 = r3 + c.k[r2&63]
|
||||
|
||||
// perform 5 mixing rounds
|
||||
for j <= 60 {
|
||||
// mix up r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
r0 = rotl16(r0, 1)
|
||||
j++
|
||||
|
||||
// mix up r1
|
||||
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
|
||||
r1 = rotl16(r1, 2)
|
||||
j++
|
||||
|
||||
// mix up r2
|
||||
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
|
||||
r2 = rotl16(r2, 3)
|
||||
j++
|
||||
|
||||
// mix up r3
|
||||
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
|
||||
r3 = rotl16(r3, 5)
|
||||
j++
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint16(dst[0:2], r0)
|
||||
binary.LittleEndian.PutUint16(dst[2:4], r1)
|
||||
binary.LittleEndian.PutUint16(dst[4:6], r2)
|
||||
binary.LittleEndian.PutUint16(dst[6:BlockSize], r3)
|
||||
}
|
||||
|
||||
func (c *rc2Cipher) Decrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("rc2: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("rc2: output not full block")
|
||||
}
|
||||
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("rc2: invalid buffer overlap")
|
||||
}
|
||||
r0 := binary.LittleEndian.Uint16(src[0:2])
|
||||
r1 := binary.LittleEndian.Uint16(src[2:4])
|
||||
r2 := binary.LittleEndian.Uint16(src[4:6])
|
||||
r3 := binary.LittleEndian.Uint16(src[6:BlockSize])
|
||||
|
||||
j := 63
|
||||
|
||||
// perform 5 r-mixing rounds
|
||||
for j >= 44 {
|
||||
// unmix r3
|
||||
r3 = rotl16(r3, 16-5)
|
||||
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
|
||||
j--
|
||||
|
||||
// unmix r2
|
||||
r2 = rotl16(r2, 16-3)
|
||||
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
|
||||
j--
|
||||
|
||||
// unmix r1
|
||||
r1 = rotl16(r1, 16-2)
|
||||
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
|
||||
j--
|
||||
|
||||
// unmix r0
|
||||
r0 = rotl16(r0, 16-1)
|
||||
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
|
||||
j--
|
||||
}
|
||||
|
||||
// perform 1 r-mashing round
|
||||
r3 = r3 - c.k[r2&63]
|
||||
r2 = r2 - c.k[r1&63]
|
||||
r1 = r1 - c.k[r0&63]
|
||||
r0 = r0 - c.k[r3&63]
|
||||
|
||||
// perform 6 r-mixing rounds
|
||||
for j >= 20 {
|
||||
// unmix r3
|
||||
r3 = rotl16(r3, 16-5)
|
||||
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
|
||||
j--
|
||||
|
||||
// unmix r2
|
||||
r2 = rotl16(r2, 16-3)
|
||||
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
|
||||
j--
|
||||
|
||||
// unmix r1
|
||||
r1 = rotl16(r1, 16-2)
|
||||
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
|
||||
j--
|
||||
|
||||
// unmix r0
|
||||
r0 = rotl16(r0, 16-1)
|
||||
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
|
||||
j--
|
||||
}
|
||||
|
||||
// perform 1 r-mashing round
|
||||
r3 = r3 - c.k[r2&63]
|
||||
r2 = r2 - c.k[r1&63]
|
||||
r1 = r1 - c.k[r0&63]
|
||||
r0 = r0 - c.k[r3&63]
|
||||
|
||||
// perform 5 r-mixing rounds
|
||||
for j >= 3 {
|
||||
// unmix r3
|
||||
r3 = rotl16(r3, 16-5)
|
||||
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
|
||||
j--
|
||||
|
||||
// unmix r2
|
||||
r2 = rotl16(r2, 16-3)
|
||||
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
|
||||
j--
|
||||
|
||||
// unmix r1
|
||||
r1 = rotl16(r1, 16-2)
|
||||
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
|
||||
j--
|
||||
|
||||
// unmix r0
|
||||
r0 = rotl16(r0, 16-1)
|
||||
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
|
||||
j--
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint16(dst[0:2], r0)
|
||||
binary.LittleEndian.PutUint16(dst[2:4], r1)
|
||||
binary.LittleEndian.PutUint16(dst[4:6], r2)
|
||||
binary.LittleEndian.PutUint16(dst[6:BlockSize], r3)
|
||||
}
|
96
pkcs/internal/rc2/rc2_test.go
Normal file
96
pkcs/internal/rc2/rc2_test.go
Normal file
@ -0,0 +1,96 @@
|
||||
// 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 (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
// TODO(dgryski): add the rest of the test vectors from the RFC
|
||||
var tests = []struct {
|
||||
key string
|
||||
plain string
|
||||
cipher string
|
||||
t1 int
|
||||
}{
|
||||
{
|
||||
"0000000000000000",
|
||||
"0000000000000000",
|
||||
"ebb773f993278eff",
|
||||
63,
|
||||
},
|
||||
{
|
||||
"ffffffffffffffff",
|
||||
"ffffffffffffffff",
|
||||
"278b27e42e2f0d49",
|
||||
64,
|
||||
},
|
||||
{
|
||||
"3000000000000000",
|
||||
"1000000000000001",
|
||||
"30649edf9be7d2c2",
|
||||
64,
|
||||
},
|
||||
{
|
||||
"88",
|
||||
"0000000000000000",
|
||||
"61a8a244adacccf0",
|
||||
64,
|
||||
},
|
||||
{
|
||||
"88bca90e90875a",
|
||||
"0000000000000000",
|
||||
"6ccf4308974c267f",
|
||||
64,
|
||||
},
|
||||
{
|
||||
"88bca90e90875a7f0f79c384627bafb2",
|
||||
"0000000000000000",
|
||||
"1a807d272bbe5db1",
|
||||
64,
|
||||
},
|
||||
{
|
||||
"88bca90e90875a7f0f79c384627bafb2",
|
||||
"0000000000000000",
|
||||
"2269552ab0f85ca6",
|
||||
128,
|
||||
},
|
||||
{
|
||||
"88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e",
|
||||
"0000000000000000",
|
||||
"5b78d3a43dfff1f1",
|
||||
129,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
k, _ := hex.DecodeString(tt.key)
|
||||
p, _ := hex.DecodeString(tt.plain)
|
||||
c, _ := hex.DecodeString(tt.cipher)
|
||||
|
||||
b, err := NewCipherWithEffectiveKeyBits(k, tt.t1)
|
||||
if err != nil {
|
||||
t.Errorf("New(%q, %d) failed: %v", tt.key, tt.t1, err)
|
||||
continue
|
||||
}
|
||||
|
||||
var dst [8]byte
|
||||
|
||||
b.Encrypt(dst[:], p)
|
||||
|
||||
if !bytes.Equal(dst[:], c) {
|
||||
t.Errorf("encrypt failed: got % 2x wanted % 2x\n", dst, c)
|
||||
}
|
||||
|
||||
b.Decrypt(dst[:], c)
|
||||
|
||||
if !bytes.Equal(dst[:], p) {
|
||||
t.Errorf("decrypt failed: got % 2x wanted % 2x\n", dst, p)
|
||||
}
|
||||
}
|
||||
}
|
99
pkcs/pkcs5_pbes1.go
Normal file
99
pkcs/pkcs5_pbes1.go
Normal file
@ -0,0 +1,99 @@
|
||||
package pkcs
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"hash"
|
||||
|
||||
"github.com/emmansun/gmsm/pkcs/internal/md2"
|
||||
"github.com/emmansun/gmsm/pkcs/internal/rc2"
|
||||
)
|
||||
|
||||
var (
|
||||
pbeWithMD2AndDESCBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 1}
|
||||
pbeWithMD2AndRC2CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 4}
|
||||
pbeWithMD5AndDESCBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 3}
|
||||
pbeWithMD5AndRC2CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 6}
|
||||
pbeWithSHA1AndDESCBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 10}
|
||||
pbeWithSHA1AndRC2CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 11}
|
||||
)
|
||||
|
||||
type pbeParameter struct {
|
||||
Salt []byte
|
||||
Iteration int
|
||||
}
|
||||
|
||||
// PBES1 implements the Password-Based Encryption Scheme 1.
|
||||
type PBES1 struct {
|
||||
Algorithm pkix.AlgorithmIdentifier
|
||||
}
|
||||
|
||||
// Key returns the key derived from the password according PBKDF1.
|
||||
func (pbes1 *PBES1) Key(password []byte) ([]byte, error) {
|
||||
param := new(pbeParameter)
|
||||
if _, err := asn1.Unmarshal(pbes1.Algorithm.Parameters.FullBytes, param); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var hash hash.Hash
|
||||
switch {
|
||||
case pbes1.Algorithm.Algorithm.Equal(pbeWithMD2AndDESCBC) || pbes1.Algorithm.Algorithm.Equal(pbeWithMD2AndRC2CBC):
|
||||
hash = md2.New()
|
||||
case pbes1.Algorithm.Algorithm.Equal(pbeWithMD5AndDESCBC) || pbes1.Algorithm.Algorithm.Equal(pbeWithMD5AndRC2CBC):
|
||||
hash = md5.New()
|
||||
case pbes1.Algorithm.Algorithm.Equal(pbeWithSHA1AndDESCBC) || pbes1.Algorithm.Algorithm.Equal(pbeWithSHA1AndRC2CBC):
|
||||
hash = sha1.New()
|
||||
default:
|
||||
return nil, errors.New("pkcs5: unsupported pbes1 cipher")
|
||||
}
|
||||
hash.Write(password)
|
||||
hash.Write(param.Salt)
|
||||
key := hash.Sum(nil)
|
||||
for i := 1; i < param.Iteration; i++ {
|
||||
hash.Reset()
|
||||
hash.Write(key)
|
||||
key = hash.Sum(key[:0])
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (pbes1 *PBES1) Decrypt(password, ciphertext []byte) ([]byte, KDFParameters, error) {
|
||||
key, err := pbes1.Key(password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var block cipher.Block
|
||||
switch {
|
||||
case pbes1.Algorithm.Algorithm.Equal(pbeWithMD2AndDESCBC) ||
|
||||
pbes1.Algorithm.Algorithm.Equal(pbeWithMD5AndDESCBC) ||
|
||||
pbes1.Algorithm.Algorithm.Equal(pbeWithSHA1AndDESCBC):
|
||||
block, err = des.NewCipher(key[:8])
|
||||
case pbes1.Algorithm.Algorithm.Equal(pbeWithMD2AndRC2CBC) ||
|
||||
pbes1.Algorithm.Algorithm.Equal(pbeWithMD5AndRC2CBC) ||
|
||||
pbes1.Algorithm.Algorithm.Equal(pbeWithSHA1AndRC2CBC):
|
||||
block, err = rc2.NewCipher(key[:8])
|
||||
default:
|
||||
return nil, nil, errors.New("pkcs5: unsupported pbes1 cipher")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
plaintext, err := cbcDecrypt(block, key[8:16], ciphertext)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return plaintext, nil, nil
|
||||
}
|
||||
|
||||
func IsPBES1(algorithm pkix.AlgorithmIdentifier) bool {
|
||||
return algorithm.Algorithm.Equal(pbeWithMD2AndDESCBC) ||
|
||||
algorithm.Algorithm.Equal(pbeWithMD2AndRC2CBC) ||
|
||||
algorithm.Algorithm.Equal(pbeWithMD5AndDESCBC) ||
|
||||
algorithm.Algorithm.Equal(pbeWithMD5AndRC2CBC) ||
|
||||
algorithm.Algorithm.Equal(pbeWithSHA1AndDESCBC) ||
|
||||
algorithm.Algorithm.Equal(pbeWithSHA1AndRC2CBC)
|
||||
}
|
@ -94,6 +94,10 @@ type KDFOpts interface {
|
||||
OID() asn1.ObjectIdentifier
|
||||
}
|
||||
|
||||
type PBESEncrypter interface {
|
||||
Encrypt(rand io.Reader, password, plaintext []byte) (*pkix.AlgorithmIdentifier, []byte, error)
|
||||
}
|
||||
|
||||
// KDFParameters contains parameters (salt, etc.) for a key deriviation function.
|
||||
// It must be a ASN.1-decodable structure.
|
||||
// An implementation of this interface is created when decoding an encrypted PKCS#8 key.
|
@ -20,6 +20,7 @@ type Opts = pkcs.PBES2Opts
|
||||
type PBKDF2Opts = pkcs.PBKDF2Opts
|
||||
type ScryptOpts = pkcs.ScryptOpts
|
||||
|
||||
var DefaultOpts = pkcs.DefaultOpts
|
||||
var SM3 = pkcs.SM3
|
||||
var SHA1 = pkcs.SHA1
|
||||
var SHA224 = pkcs.SHA224
|
||||
@ -54,20 +55,25 @@ func ParsePrivateKey(der []byte, password []byte) (any, pkcs.KDFParameters, erro
|
||||
return nil, nil, errors.New("pkcs8: only PKCS #5 v2.0 supported")
|
||||
}
|
||||
|
||||
if !pkcs.IsPBES2(privKey.EncryptionAlgorithm) {
|
||||
return nil, nil, errors.New("pkcs8: only PBES2 supported")
|
||||
var kdfParams pkcs.KDFParameters
|
||||
var decryptedKey []byte
|
||||
var err error
|
||||
switch {
|
||||
case pkcs.IsPBES2(privKey.EncryptionAlgorithm):
|
||||
var params pkcs.PBES2Params
|
||||
if _, err := asn1.Unmarshal(privKey.EncryptionAlgorithm.Parameters.FullBytes, ¶ms); err != nil {
|
||||
return nil, nil, errors.New("pkcs8: invalid PBES2 parameters")
|
||||
}
|
||||
decryptedKey, kdfParams, err = params.Decrypt(password, privKey.EncryptedData)
|
||||
case pkcs.IsPBES1(privKey.EncryptionAlgorithm):
|
||||
pbes1 := &pkcs.PBES1{Algorithm: privKey.EncryptionAlgorithm}
|
||||
decryptedKey, kdfParams, err = pbes1.Decrypt(password, privKey.EncryptedData)
|
||||
default:
|
||||
return nil, nil, errors.New("pkcs8: only part of PBES1/PBES2 supported")
|
||||
}
|
||||
|
||||
var params pkcs.PBES2Params
|
||||
if _, err := asn1.Unmarshal(privKey.EncryptionAlgorithm.Parameters.FullBytes, ¶ms); err != nil {
|
||||
return nil, nil, errors.New("pkcs8: invalid PBES2 parameters")
|
||||
}
|
||||
|
||||
decryptedKey, kdfParams, err := params.Decrypt(password, privKey.EncryptedData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
key, err := smx509.ParsePKCS8PrivateKey(decryptedKey)
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("pkcs8: incorrect password? failed to parse private key while ParsePKCS8PrivateKey: " + err.Error())
|
||||
@ -77,13 +83,13 @@ func ParsePrivateKey(der []byte, password []byte) (any, pkcs.KDFParameters, erro
|
||||
|
||||
// MarshalPrivateKey encodes a private key into DER-encoded PKCS#8 with the given options.
|
||||
// Password can be nil.
|
||||
func MarshalPrivateKey(priv any, password []byte, opts *Opts) ([]byte, error) {
|
||||
func MarshalPrivateKey(priv any, password []byte, encrypter pkcs.PBESEncrypter) ([]byte, error) {
|
||||
if len(password) == 0 {
|
||||
return smx509.MarshalPKCS8PrivateKey(priv)
|
||||
}
|
||||
|
||||
if opts == nil {
|
||||
opts = pkcs.DefaultOpts
|
||||
if encrypter == nil {
|
||||
encrypter = DefaultOpts
|
||||
}
|
||||
|
||||
// Convert private key into PKCS8 format
|
||||
@ -92,7 +98,7 @@ func MarshalPrivateKey(priv any, password []byte, opts *Opts) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encryptionAlgorithm, encryptedKey, err := opts.Encrypt(rand.Reader, password, pkey)
|
||||
encryptionAlgorithm, encryptedKey, err := encrypter.Encrypt(rand.Reader, password, pkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -181,6 +181,38 @@ zOuhMC9Oo3oMYlbEXAT9mq33MkGKMUth2ek/bQIvnCHG
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
`
|
||||
|
||||
const encryptedPBEWithMD5AndDES = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGwMBsGCSqGSIb3DQEFAzAOBAhsKeK+cnfdjAICCAAEgZAE5GZMjPQCLLifGK0r
|
||||
ytlpt23Qas1KI6x7qmIP6oeYflCWT0Iv7AqK2cT8YK7s5Yy3j21YiHEG5FCr8Qb+
|
||||
GMlgQsRGkeU5y0I9zLZrhH9qOVJEuDLckCjMKbFXUEwx5YeBhQKTosB/quA5v9Lp
|
||||
6SSLtKShYgx/MDJDarcAuj0whmNyTXijDGAMImltuqwsIUg=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
`
|
||||
|
||||
const encyptedPBEWithSha1AndDES = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGwMBsGCSqGSIb3DQEFCjAOBAiFq+R6absk/wICCAAEgZB7T7BEaGkyMqw8xN9e
|
||||
ldSPFAAXzcsPx83w1jvD8TvM7uwqUu9k0+2FnSMcuhOHjX03AFZ2JJXZZBWxZJ24
|
||||
GEWLwQYJIJ16el9n2DVPkp1qqbsXPMCyHR9hW4Qxt/9aXZmTLdqpAhQ9BfTSmpQp
|
||||
Yt+/s6eXMOHP2C0sp5aOxnIjkorzfgasO/Y8JtMukVlKzqU=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
`
|
||||
|
||||
const encryptedPBEWithSha1AndRC2_64 = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGwMBsGCSqGSIb3DQEFCzAOBAhNHGnZio3lKwICCAAEgZCGUGQ3b6zS/iBlJ6BY
|
||||
mpmuPBmGnuwtOtTFshWaZL8kPUROkZVBrKt6a/oM0vsTbyEDeii9ktt2cnd3plwh
|
||||
fqnOmJmOBwHVeltjRLYYFzs2JgX4bXSc9eg+/AugvsDPj+dgk0yMsRLjKoZw/w/U
|
||||
qZTZq/iFYg4Q80Ew7gJUBaMdA6Af8K/YDc3If7y78L0AD74=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
`
|
||||
|
||||
const encryptedPBEWithMD5AndRC2_40 = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGwMBsGCSqGSIb3DQEFBjAOBAiZRjrXPXpYwgICCAAEgZBilgJ9rYtNt7Ih59zF
|
||||
jnErhxny2wRPoK1Ng/bLNijlBnppryizyAHuujNmpDRf77pYFmszaaprWZDs2bQw
|
||||
tlhqw20XVOBG2PhHXsL9LXfbm7lJOVpMtBYtbduascC1aA5Dref9L3nBNlP5zdMp
|
||||
TFgdUgkic4/tuw6b5E3Ysn3ugAlPTAMm7b8Nd0Hs0P/81nA=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
`
|
||||
|
||||
func TestParsePKCS8PrivateKeyRSA(t *testing.T) {
|
||||
keyList := []struct {
|
||||
name string
|
||||
@ -711,8 +743,8 @@ func TestParseInvalidPrivateKey(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = pkcs8.ParsePKCS8PrivateKeyECDSA(data, []byte("password"))
|
||||
if err == nil || err.Error() != "pkcs8: only PBES2 supported" {
|
||||
t.Errorf("should be error: pkcs8: only PBES2 supported")
|
||||
if err == nil || err.Error() != "pkcs8: only part of PBES1/PBES2 supported" {
|
||||
t.Errorf("should be error: only part of PBES1/PBES2 supported")
|
||||
}
|
||||
|
||||
privKey.EncryptionAlgorithm.Algorithm = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13}
|
||||
@ -725,3 +757,34 @@ func TestParseInvalidPrivateKey(t *testing.T) {
|
||||
t.Errorf("should be error: pkcs8: invalid PBES2 parameters")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseLegacyPBES1PrivateKey(t *testing.T) {
|
||||
block, _ := pem.Decode([]byte(encryptedPBEWithMD5AndDES))
|
||||
_, err := pkcs8.ParsePKCS8PrivateKey(block.Bytes, []byte("12345678"))
|
||||
if err != nil {
|
||||
t.Errorf("ParsePKCS8PrivateKey returned: %s", err)
|
||||
}
|
||||
|
||||
block, _ = pem.Decode([]byte(encyptedPBEWithSha1AndDES))
|
||||
_, err = pkcs8.ParsePKCS8PrivateKey(block.Bytes, []byte("12345678"))
|
||||
if err != nil {
|
||||
t.Errorf("ParsePKCS8PrivateKey returned: %s", err)
|
||||
}
|
||||
|
||||
block, _ = pem.Decode([]byte(encryptedPBEWithSha1AndRC2_64))
|
||||
_, err = pkcs8.ParsePKCS8PrivateKey(block.Bytes, []byte("12345678"))
|
||||
if err != nil {
|
||||
t.Errorf("ParsePKCS8PrivateKey returned: %s", err)
|
||||
}
|
||||
|
||||
block, _ = pem.Decode([]byte(encryptedPBEWithMD5AndRC2_40))
|
||||
_, err = pkcs8.ParsePKCS8PrivateKey(block.Bytes, []byte("12345678"))
|
||||
if err != nil {
|
||||
t.Errorf("ParsePKCS8PrivateKey returned: %s", err)
|
||||
}
|
||||
|
||||
_, err = pkcs8.ParsePKCS8PrivateKey(block.Bytes, []byte("wrong pwd"))
|
||||
if err == nil {
|
||||
t.Errorf("should have failed")
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user