vendor: add pkcs8 helpers for decrypting encrypted private keys
This commit is contained in:
parent
1031bcfc5a
commit
643192b347
9 changed files with 390 additions and 2 deletions
1
go.mod
1
go.mod
|
@ -53,6 +53,7 @@ require (
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
github.com/t3rm1n4l/go-mega v0.0.0-20190528125457-55e675378686
|
github.com/t3rm1n4l/go-mega v0.0.0-20190528125457-55e675378686
|
||||||
github.com/xanzy/ssh-agent v0.2.1
|
github.com/xanzy/ssh-agent v0.2.1
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20181201043747-70daafe5d78a
|
||||||
github.com/yunify/qingstor-sdk-go/v3 v3.0.2
|
github.com/yunify/qingstor-sdk-go/v3 v3.0.2
|
||||||
go.etcd.io/bbolt v1.3.3 // indirect
|
go.etcd.io/bbolt v1.3.3 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -234,6 +234,8 @@ github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS
|
||||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20181201043747-70daafe5d78a h1:wRlvyDgRuJOLgD2vcuBUbEduzTkcN7quLip1EnX/Dl4=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20181201043747-70daafe5d78a/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||||
github.com/yunify/qingstor-sdk-go/v3 v3.0.2 h1:2pL3tEj6eEESsHKrqsLZ5D+OkHEhYfsW1xwYRcHCgZs=
|
github.com/yunify/qingstor-sdk-go/v3 v3.0.2 h1:2pL3tEj6eEESsHKrqsLZ5D+OkHEhYfsW1xwYRcHCgZs=
|
||||||
github.com/yunify/qingstor-sdk-go/v3 v3.0.2/go.mod h1:KciFNuMu6F4WLk9nGwwK69sCGKLCdd9f97ac/wfumS4=
|
github.com/yunify/qingstor-sdk-go/v3 v3.0.2/go.mod h1:KciFNuMu6F4WLk9nGwwK69sCGKLCdd9f97ac/wfumS4=
|
||||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||||
|
|
23
vendor/github.com/youmark/pkcs8/.gitignore
generated
vendored
Normal file
23
vendor/github.com/youmark/pkcs8/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
9
vendor/github.com/youmark/pkcs8/.travis.yml
generated
vendored
Normal file
9
vendor/github.com/youmark/pkcs8/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- "1.9.x"
|
||||||
|
- "1.10.x"
|
||||||
|
- master
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -v ./...
|
21
vendor/github.com/youmark/pkcs8/LICENSE
generated
vendored
Normal file
21
vendor/github.com/youmark/pkcs8/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 youmark
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
1
vendor/github.com/youmark/pkcs8/README
generated
vendored
Normal file
1
vendor/github.com/youmark/pkcs8/README
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pkcs8 package: implement PKCS#8 private key parsing and conversion as defined in RFC5208 and RFC5958
|
21
vendor/github.com/youmark/pkcs8/README.md
generated
vendored
Normal file
21
vendor/github.com/youmark/pkcs8/README.md
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
pkcs8
|
||||||
|
===
|
||||||
|
OpenSSL can generate private keys in both "traditional format" and PKCS#8 format. Newer applications are advised to use more secure PKCS#8 format. Go standard crypto package provides a [function](http://golang.org/pkg/crypto/x509/#ParsePKCS8PrivateKey) to parse private key in PKCS#8 format. There is a limitation to this function. It can only handle unencrypted PKCS#8 private keys. To use this function, the user has to save the private key in file without encryption, which is a bad practice to leave private keys unprotected on file systems. In addition, Go standard package lacks the functions to convert RSA/ECDSA private keys into PKCS#8 format.
|
||||||
|
|
||||||
|
pkcs8 package fills the gap here. It implements functions to process private keys in PKCS#8 format, as defined in [RFC5208](https://tools.ietf.org/html/rfc5208) and [RFC5958](https://tools.ietf.org/html/rfc5958). It can handle both unencrypted PKCS#8 PrivateKeyInfo format and EncryptedPrivateKeyInfo format with PKCS#5 (v2.0) algorithms.
|
||||||
|
|
||||||
|
|
||||||
|
[**Godoc**](http://godoc.org/github.com/youmark/pkcs8)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
Supports Go 1.9+
|
||||||
|
|
||||||
|
```text
|
||||||
|
go get github.com/youmark/pkcs8
|
||||||
|
```
|
||||||
|
## dependency
|
||||||
|
This package depends on golang.org/x/crypto/pbkdf2 package. Use the following command to retrive pbkdf2 package
|
||||||
|
```text
|
||||||
|
go get golang.org/x/crypto/pbkdf2
|
||||||
|
```
|
||||||
|
|
308
vendor/github.com/youmark/pkcs8/pkcs8.go
generated
vendored
Normal file
308
vendor/github.com/youmark/pkcs8/pkcs8.go
generated
vendored
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
// Package pkcs8 implements functions to parse and convert private keys in PKCS#8 format, as defined in RFC5208 and RFC5958
|
||||||
|
package pkcs8
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copy from crypto/x509
|
||||||
|
var (
|
||||||
|
oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||||
|
oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
|
||||||
|
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copy from crypto/x509
|
||||||
|
var (
|
||||||
|
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
|
||||||
|
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
|
||||||
|
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
|
||||||
|
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copy from crypto/x509
|
||||||
|
func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
|
||||||
|
switch curve {
|
||||||
|
case elliptic.P224():
|
||||||
|
return oidNamedCurveP224, true
|
||||||
|
case elliptic.P256():
|
||||||
|
return oidNamedCurveP256, true
|
||||||
|
case elliptic.P384():
|
||||||
|
return oidNamedCurveP384, true
|
||||||
|
case elliptic.P521():
|
||||||
|
return oidNamedCurveP521, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unecrypted PKCS8
|
||||||
|
var (
|
||||||
|
oidPKCS5PBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12}
|
||||||
|
oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13}
|
||||||
|
oidAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
|
||||||
|
oidAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
|
||||||
|
oidHMACWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9}
|
||||||
|
oidDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7}
|
||||||
|
)
|
||||||
|
|
||||||
|
type ecPrivateKey struct {
|
||||||
|
Version int
|
||||||
|
PrivateKey []byte
|
||||||
|
NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
|
||||||
|
PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type privateKeyInfo struct {
|
||||||
|
Version int
|
||||||
|
PrivateKeyAlgorithm []asn1.ObjectIdentifier
|
||||||
|
PrivateKey []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypted PKCS8
|
||||||
|
type prfParam struct {
|
||||||
|
IdPRF asn1.ObjectIdentifier
|
||||||
|
NullParam asn1.RawValue
|
||||||
|
}
|
||||||
|
|
||||||
|
type pbkdf2Params struct {
|
||||||
|
Salt []byte
|
||||||
|
IterationCount int
|
||||||
|
PrfParam prfParam `asn1:"optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type pbkdf2Algorithms struct {
|
||||||
|
IdPBKDF2 asn1.ObjectIdentifier
|
||||||
|
PBKDF2Params pbkdf2Params
|
||||||
|
}
|
||||||
|
|
||||||
|
type pbkdf2Encs struct {
|
||||||
|
EncryAlgo asn1.ObjectIdentifier
|
||||||
|
IV []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type pbes2Params struct {
|
||||||
|
KeyDerivationFunc pbkdf2Algorithms
|
||||||
|
EncryptionScheme pbkdf2Encs
|
||||||
|
}
|
||||||
|
|
||||||
|
type pbes2Algorithms struct {
|
||||||
|
IdPBES2 asn1.ObjectIdentifier
|
||||||
|
PBES2Params pbes2Params
|
||||||
|
}
|
||||||
|
|
||||||
|
type encryptedPrivateKeyInfo struct {
|
||||||
|
EncryptionAlgorithm pbes2Algorithms
|
||||||
|
EncryptedData []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePKCS8PrivateKeyRSA parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
|
||||||
|
//
|
||||||
|
// The function can decrypt the private key encrypted with AES-256-CBC mode, and stored in PKCS #5 v2.0 format.
|
||||||
|
func ParsePKCS8PrivateKeyRSA(der []byte, v ...[]byte) (*rsa.PrivateKey, error) {
|
||||||
|
key, err := ParsePKCS8PrivateKey(der, v...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
typedKey, ok := key.(*rsa.PrivateKey)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("key block is not of type RSA")
|
||||||
|
}
|
||||||
|
return typedKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePKCS8PrivateKeyECDSA parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
|
||||||
|
//
|
||||||
|
// The function can decrypt the private key encrypted with AES-256-CBC mode, and stored in PKCS #5 v2.0 format.
|
||||||
|
func ParsePKCS8PrivateKeyECDSA(der []byte, v ...[]byte) (*ecdsa.PrivateKey, error) {
|
||||||
|
key, err := ParsePKCS8PrivateKey(der, v...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
typedKey, ok := key.(*ecdsa.PrivateKey)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("key block is not of type ECDSA")
|
||||||
|
}
|
||||||
|
return typedKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePKCS8PrivateKey parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
|
||||||
|
//
|
||||||
|
// The function can decrypt the private key encrypted with AES-256-CBC mode, and stored in PKCS #5 v2.0 format.
|
||||||
|
func ParsePKCS8PrivateKey(der []byte, v ...[]byte) (interface{}, error) {
|
||||||
|
// No password provided, assume the private key is unencrypted
|
||||||
|
if v == nil {
|
||||||
|
return x509.ParsePKCS8PrivateKey(der)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the password provided to decrypt the private key
|
||||||
|
password := v[0]
|
||||||
|
var privKey encryptedPrivateKeyInfo
|
||||||
|
if _, err := asn1.Unmarshal(der, &privKey); err != nil {
|
||||||
|
return nil, errors.New("pkcs8: only PKCS #5 v2.0 supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !privKey.EncryptionAlgorithm.IdPBES2.Equal(oidPBES2) {
|
||||||
|
return nil, errors.New("pkcs8: only PBES2 supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !privKey.EncryptionAlgorithm.PBES2Params.KeyDerivationFunc.IdPBKDF2.Equal(oidPKCS5PBKDF2) {
|
||||||
|
return nil, errors.New("pkcs8: only PBKDF2 supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
encParam := privKey.EncryptionAlgorithm.PBES2Params.EncryptionScheme
|
||||||
|
kdfParam := privKey.EncryptionAlgorithm.PBES2Params.KeyDerivationFunc.PBKDF2Params
|
||||||
|
|
||||||
|
iv := encParam.IV
|
||||||
|
salt := kdfParam.Salt
|
||||||
|
iter := kdfParam.IterationCount
|
||||||
|
keyHash := sha1.New
|
||||||
|
if kdfParam.PrfParam.IdPRF.Equal(oidHMACWithSHA256) {
|
||||||
|
keyHash = sha256.New
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedKey := privKey.EncryptedData
|
||||||
|
var symkey []byte
|
||||||
|
var block cipher.Block
|
||||||
|
var err error
|
||||||
|
switch {
|
||||||
|
case encParam.EncryAlgo.Equal(oidAES128CBC):
|
||||||
|
symkey = pbkdf2.Key(password, salt, iter, 16, keyHash)
|
||||||
|
block, err = aes.NewCipher(symkey)
|
||||||
|
case encParam.EncryAlgo.Equal(oidAES256CBC):
|
||||||
|
symkey = pbkdf2.Key(password, salt, iter, 32, keyHash)
|
||||||
|
block, err = aes.NewCipher(symkey)
|
||||||
|
case encParam.EncryAlgo.Equal(oidDESEDE3CBC):
|
||||||
|
symkey = pbkdf2.Key(password, salt, iter, 24, keyHash)
|
||||||
|
block, err = des.NewTripleDESCipher(symkey)
|
||||||
|
default:
|
||||||
|
return nil, errors.New("pkcs8: only AES-256-CBC, AES-128-CBC and DES-EDE3-CBC are supported")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mode := cipher.NewCBCDecrypter(block, iv)
|
||||||
|
mode.CryptBlocks(encryptedKey, encryptedKey)
|
||||||
|
|
||||||
|
key, err := x509.ParsePKCS8PrivateKey(encryptedKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("pkcs8: incorrect password")
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertPrivateKeyToPKCS8(priv interface{}) ([]byte, error) {
|
||||||
|
var pkey privateKeyInfo
|
||||||
|
|
||||||
|
switch priv := priv.(type) {
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
eckey, err := x509.MarshalECPrivateKey(priv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
oidNamedCurve, ok := oidFromNamedCurve(priv.Curve)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("pkcs8: unknown elliptic curve")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per RFC5958, if publicKey is present, then version is set to v2(1) else version is set to v1(0).
|
||||||
|
// But openssl set to v1 even publicKey is present
|
||||||
|
pkey.Version = 1
|
||||||
|
pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 2)
|
||||||
|
pkey.PrivateKeyAlgorithm[0] = oidPublicKeyECDSA
|
||||||
|
pkey.PrivateKeyAlgorithm[1] = oidNamedCurve
|
||||||
|
pkey.PrivateKey = eckey
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
|
||||||
|
// Per RFC5958, if publicKey is present, then version is set to v2(1) else version is set to v1(0).
|
||||||
|
// But openssl set to v1 even publicKey is present
|
||||||
|
pkey.Version = 0
|
||||||
|
pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
|
||||||
|
pkey.PrivateKeyAlgorithm[0] = oidPublicKeyRSA
|
||||||
|
pkey.PrivateKey = x509.MarshalPKCS1PrivateKey(priv)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported key type: %T", priv)
|
||||||
|
}
|
||||||
|
|
||||||
|
return asn1.Marshal(pkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertPrivateKeyToPKCS8Encrypted(priv interface{}, password []byte) ([]byte, error) {
|
||||||
|
// Convert private key into PKCS8 format
|
||||||
|
pkey, err := convertPrivateKeyToPKCS8(priv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate key from password based on PKCS5 algorithm
|
||||||
|
// Use 8 byte salt, 16 byte IV, and 2048 iteration
|
||||||
|
iter := 2048
|
||||||
|
salt := make([]byte, 8)
|
||||||
|
iv := make([]byte, 16)
|
||||||
|
_, err = rand.Read(salt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = rand.Read(iv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key := pbkdf2.Key(password, salt, iter, 32, sha256.New)
|
||||||
|
|
||||||
|
// Use AES256-CBC mode, pad plaintext with PKCS5 padding scheme
|
||||||
|
padding := aes.BlockSize - len(pkey)%aes.BlockSize
|
||||||
|
if padding > 0 {
|
||||||
|
n := len(pkey)
|
||||||
|
pkey = append(pkey, make([]byte, padding)...)
|
||||||
|
for i := 0; i < padding; i++ {
|
||||||
|
pkey[n+i] = byte(padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedKey := make([]byte, len(pkey))
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
mode.CryptBlocks(encryptedKey, pkey)
|
||||||
|
|
||||||
|
// pbkdf2algo := pbkdf2Algorithms{oidPKCS5PBKDF2, pbkdf2Params{salt, iter, prfParam{oidHMACWithSHA256}}}
|
||||||
|
|
||||||
|
pbkdf2algo := pbkdf2Algorithms{oidPKCS5PBKDF2, pbkdf2Params{salt, iter, prfParam{oidHMACWithSHA256, asn1.RawValue{Tag: asn1.TagNull}}}}
|
||||||
|
pbkdf2encs := pbkdf2Encs{oidAES256CBC, iv}
|
||||||
|
pbes2algo := pbes2Algorithms{oidPBES2, pbes2Params{pbkdf2algo, pbkdf2encs}}
|
||||||
|
|
||||||
|
encryptedPkey := encryptedPrivateKeyInfo{pbes2algo, encryptedKey}
|
||||||
|
|
||||||
|
return asn1.Marshal(encryptedPkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertPrivateKeyToPKCS8 converts the private key into PKCS#8 format.
|
||||||
|
// To encrypt the private key, the password of []byte type should be provided as the second parameter.
|
||||||
|
//
|
||||||
|
// The only supported key types are RSA and ECDSA (*rsa.PrivateKey or *ecdsa.PrivateKey for priv)
|
||||||
|
func ConvertPrivateKeyToPKCS8(priv interface{}, v ...[]byte) ([]byte, error) {
|
||||||
|
if v == nil {
|
||||||
|
return convertPrivateKeyToPKCS8(priv)
|
||||||
|
}
|
||||||
|
|
||||||
|
password := v[0]
|
||||||
|
return convertPrivateKeyToPKCS8Encrypted(priv, password)
|
||||||
|
}
|
6
vendor/modules.txt
vendored
6
vendor/modules.txt
vendored
|
@ -172,6 +172,8 @@ github.com/stretchr/testify/require
|
||||||
github.com/t3rm1n4l/go-mega
|
github.com/t3rm1n4l/go-mega
|
||||||
# github.com/xanzy/ssh-agent v0.2.1
|
# github.com/xanzy/ssh-agent v0.2.1
|
||||||
github.com/xanzy/ssh-agent
|
github.com/xanzy/ssh-agent
|
||||||
|
# github.com/youmark/pkcs8 v0.0.0-20181201043747-70daafe5d78a
|
||||||
|
github.com/youmark/pkcs8
|
||||||
# github.com/yunify/qingstor-sdk-go/v3 v3.0.2
|
# github.com/yunify/qingstor-sdk-go/v3 v3.0.2
|
||||||
github.com/yunify/qingstor-sdk-go/v3/config
|
github.com/yunify/qingstor-sdk-go/v3/config
|
||||||
github.com/yunify/qingstor-sdk-go/v3/request/errors
|
github.com/yunify/qingstor-sdk-go/v3/request/errors
|
||||||
|
@ -207,10 +209,10 @@ golang.org/x/crypto/scrypt
|
||||||
golang.org/x/crypto/ssh
|
golang.org/x/crypto/ssh
|
||||||
golang.org/x/crypto/ssh/terminal
|
golang.org/x/crypto/ssh/terminal
|
||||||
golang.org/x/crypto/bcrypt
|
golang.org/x/crypto/bcrypt
|
||||||
|
golang.org/x/crypto/pbkdf2
|
||||||
golang.org/x/crypto/internal/subtle
|
golang.org/x/crypto/internal/subtle
|
||||||
golang.org/x/crypto/poly1305
|
golang.org/x/crypto/poly1305
|
||||||
golang.org/x/crypto/salsa20/salsa
|
golang.org/x/crypto/salsa20/salsa
|
||||||
golang.org/x/crypto/pbkdf2
|
|
||||||
golang.org/x/crypto/ssh/agent
|
golang.org/x/crypto/ssh/agent
|
||||||
golang.org/x/crypto/curve25519
|
golang.org/x/crypto/curve25519
|
||||||
golang.org/x/crypto/ed25519
|
golang.org/x/crypto/ed25519
|
||||||
|
@ -239,9 +241,9 @@ golang.org/x/net/trace
|
||||||
golang.org/x/net/internal/timeseries
|
golang.org/x/net/internal/timeseries
|
||||||
# golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
# golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||||
golang.org/x/oauth2
|
golang.org/x/oauth2
|
||||||
|
golang.org/x/oauth2/jws
|
||||||
golang.org/x/oauth2/google
|
golang.org/x/oauth2/google
|
||||||
golang.org/x/oauth2/internal
|
golang.org/x/oauth2/internal
|
||||||
golang.org/x/oauth2/jws
|
|
||||||
golang.org/x/oauth2/jwt
|
golang.org/x/oauth2/jwt
|
||||||
# golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
# golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||||
golang.org/x/sync/errgroup
|
golang.org/x/sync/errgroup
|
||||||
|
|
Loading…
Reference in a new issue