Added oid which is a fork of https://github.com/mastahyeti/cms/tree/master/oid; contains the needed OIDs for cryptographic message syntax.
This commit is contained in:
parent
b33189be9c
commit
9179582f90
129
oid/oid.go
Normal file
129
oid/oid.go
Normal file
@ -0,0 +1,129 @@
|
||||
// Package oid contains OIDs that are used by other packages in this repository.
|
||||
package oid
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
)
|
||||
|
||||
// Content type OIDs
|
||||
var (
|
||||
Data = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
|
||||
SignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
|
||||
EnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
|
||||
AuthEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 23}
|
||||
TSTInfo = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4}
|
||||
ContentTypeTSTInfo = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4}
|
||||
)
|
||||
|
||||
// Attribute OIDs
|
||||
var (
|
||||
AttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
|
||||
AttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
|
||||
AttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5}
|
||||
AttributeTimeStampToken = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 14}
|
||||
)
|
||||
|
||||
// Signature Algorithm OIDs
|
||||
var (
|
||||
SignatureAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||
SignatureAlgorithmECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
)
|
||||
|
||||
// Public Key Encryption OIDs
|
||||
var (
|
||||
EncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||
)
|
||||
|
||||
// Digest Algorithm OIDs
|
||||
var (
|
||||
DigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
|
||||
DigestAlgorithmMD5 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 5}
|
||||
DigestAlgorithmSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
|
||||
DigestAlgorithmSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
|
||||
DigestAlgorithmSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
|
||||
)
|
||||
|
||||
// X.509 extensions
|
||||
var (
|
||||
SubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14}
|
||||
)
|
||||
|
||||
// DigestAlgorithmToHash maps digest OIDs to crypto.Hash values.
|
||||
var DigestAlgorithmToHash = map[string]crypto.Hash{
|
||||
DigestAlgorithmSHA1.String(): crypto.SHA1,
|
||||
DigestAlgorithmMD5.String(): crypto.MD5,
|
||||
DigestAlgorithmSHA256.String(): crypto.SHA256,
|
||||
DigestAlgorithmSHA384.String(): crypto.SHA384,
|
||||
DigestAlgorithmSHA512.String(): crypto.SHA512,
|
||||
}
|
||||
|
||||
// HashToDigestAlgorithm maps crypto.Hash values to digest OIDs.
|
||||
var HashToDigestAlgorithm = map[crypto.Hash]asn1.ObjectIdentifier{
|
||||
crypto.SHA1: DigestAlgorithmSHA1,
|
||||
crypto.MD5: DigestAlgorithmMD5,
|
||||
crypto.SHA256: DigestAlgorithmSHA256,
|
||||
crypto.SHA384: DigestAlgorithmSHA384,
|
||||
crypto.SHA512: DigestAlgorithmSHA512,
|
||||
}
|
||||
|
||||
// SignatureAlgorithmToDigestAlgorithm maps x509.SignatureAlgorithm to
|
||||
// digestAlgorithm OIDs.
|
||||
var SignatureAlgorithmToDigestAlgorithm = map[x509.SignatureAlgorithm]asn1.ObjectIdentifier{
|
||||
x509.SHA1WithRSA: DigestAlgorithmSHA1,
|
||||
x509.MD5WithRSA: DigestAlgorithmMD5,
|
||||
x509.SHA256WithRSA: DigestAlgorithmSHA256,
|
||||
x509.SHA384WithRSA: DigestAlgorithmSHA384,
|
||||
x509.SHA512WithRSA: DigestAlgorithmSHA512,
|
||||
x509.ECDSAWithSHA1: DigestAlgorithmSHA1,
|
||||
x509.ECDSAWithSHA256: DigestAlgorithmSHA256,
|
||||
x509.ECDSAWithSHA384: DigestAlgorithmSHA384,
|
||||
x509.ECDSAWithSHA512: DigestAlgorithmSHA512,
|
||||
}
|
||||
|
||||
// SignatureAlgorithmToSignatureAlgorithm maps x509.SignatureAlgorithm to
|
||||
// signatureAlgorithm OIDs.
|
||||
var SignatureAlgorithmToSignatureAlgorithm = map[x509.SignatureAlgorithm]asn1.ObjectIdentifier{
|
||||
x509.SHA1WithRSA: SignatureAlgorithmRSA,
|
||||
x509.MD5WithRSA: SignatureAlgorithmRSA,
|
||||
x509.SHA256WithRSA: SignatureAlgorithmRSA,
|
||||
x509.SHA384WithRSA: SignatureAlgorithmRSA,
|
||||
x509.SHA512WithRSA: SignatureAlgorithmRSA,
|
||||
x509.ECDSAWithSHA1: SignatureAlgorithmECDSA,
|
||||
x509.ECDSAWithSHA256: SignatureAlgorithmECDSA,
|
||||
x509.ECDSAWithSHA384: SignatureAlgorithmECDSA,
|
||||
x509.ECDSAWithSHA512: SignatureAlgorithmECDSA,
|
||||
}
|
||||
|
||||
// SignatureAlgorithms maps digest and signature OIDs to
|
||||
// x509.SignatureAlgorithm values.
|
||||
var SignatureAlgorithms = map[string]map[string]x509.SignatureAlgorithm{
|
||||
SignatureAlgorithmRSA.String(): map[string]x509.SignatureAlgorithm{
|
||||
DigestAlgorithmSHA1.String(): x509.SHA1WithRSA,
|
||||
DigestAlgorithmMD5.String(): x509.MD5WithRSA,
|
||||
DigestAlgorithmSHA256.String(): x509.SHA256WithRSA,
|
||||
DigestAlgorithmSHA384.String(): x509.SHA384WithRSA,
|
||||
DigestAlgorithmSHA512.String(): x509.SHA512WithRSA,
|
||||
},
|
||||
SignatureAlgorithmECDSA.String(): map[string]x509.SignatureAlgorithm{
|
||||
DigestAlgorithmSHA1.String(): x509.ECDSAWithSHA1,
|
||||
DigestAlgorithmSHA256.String(): x509.ECDSAWithSHA256,
|
||||
DigestAlgorithmSHA384.String(): x509.ECDSAWithSHA384,
|
||||
DigestAlgorithmSHA512.String(): x509.ECDSAWithSHA512,
|
||||
},
|
||||
}
|
||||
|
||||
// PublicKeyAlgorithmToSignatureAlgorithm maps certificate public key
|
||||
// algorithms to CMS signature algorithms.
|
||||
var PublicKeyAlgorithmToSignatureAlgorithm = map[x509.PublicKeyAlgorithm]pkix.AlgorithmIdentifier{
|
||||
x509.RSA: pkix.AlgorithmIdentifier{Algorithm: SignatureAlgorithmRSA},
|
||||
x509.ECDSA: pkix.AlgorithmIdentifier{Algorithm: SignatureAlgorithmECDSA},
|
||||
}
|
||||
|
||||
// PublicKeyAlgorithmToEncrytionAlgorithm maps certificate public key
|
||||
// algorithms to CMS encryption algorithms.
|
||||
var PublicKeyAlgorithmToEncrytionAlgorithm = map[x509.PublicKeyAlgorithm]pkix.AlgorithmIdentifier{
|
||||
x509.RSA: pkix.AlgorithmIdentifier{Algorithm: EncryptionAlgorithmRSA},
|
||||
}
|
260
oid/symmetric_ciphers.go
Normal file
260
oid/symmetric_ciphers.go
Normal file
@ -0,0 +1,260 @@
|
||||
package oid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
// EncryptionAlgorithm does the handling of the encrypton and decryption for a given algorithm identifier.
|
||||
type EncryptionAlgorithm struct {
|
||||
EncryptionAlgorithmIdentifier asn1.ObjectIdentifier
|
||||
ContentEncryptionAlgorithmIdentifier pkix.AlgorithmIdentifier
|
||||
Key, IV, MAC []byte
|
||||
}
|
||||
|
||||
// Encryption Algorithm OIDs
|
||||
var (
|
||||
EncryptionAlgorithmDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7}
|
||||
EncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7}
|
||||
EncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
|
||||
EncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
|
||||
//AEAD
|
||||
EncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6}
|
||||
AEADChaCha20Poly1305 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 3, 18}
|
||||
)
|
||||
|
||||
var symmetricKeyLen = map[string]int{
|
||||
EncryptionAlgorithmDESCBC.String(): 7,
|
||||
EncryptionAlgorithmDESEDE3CBC.String(): 21,
|
||||
EncryptionAlgorithmAES128CBC.String(): 16,
|
||||
EncryptionAlgorithmAES256CBC.String(): 32,
|
||||
//AEAD
|
||||
EncryptionAlgorithmAES128GCM.String(): 16,
|
||||
AEADChaCha20Poly1305.String(): 32,
|
||||
}
|
||||
|
||||
// Encrypt encrypts the plaintext and returns the ciphertext.
|
||||
func (e *EncryptionAlgorithm) Encrypt(plaintext []byte) (ciphertext []byte, err error) {
|
||||
|
||||
if e.Key == nil {
|
||||
e.Key = make([]byte, symmetricKeyLen[e.EncryptionAlgorithmIdentifier.String()])
|
||||
rand.Read(e.Key)
|
||||
}
|
||||
|
||||
//Choose cipher
|
||||
var blockCipher cipher.Block
|
||||
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String(), EncryptionAlgorithmAES128GCM.String():
|
||||
blockCipher, err = aes.NewCipher(e.Key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case AEADChaCha20Poly1305.String():
|
||||
default:
|
||||
err = errors.New("Content encrytion: cipher not supportet")
|
||||
return
|
||||
}
|
||||
|
||||
//Choose blockmode
|
||||
var blockMode cipher.BlockMode
|
||||
var aead cipher.AEAD
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String():
|
||||
if e.IV == nil {
|
||||
e.IV = make([]byte, len(e.Key))
|
||||
rand.Read(e.IV)
|
||||
}
|
||||
|
||||
blockMode = cipher.NewCBCEncrypter(blockCipher, e.IV)
|
||||
e.ContentEncryptionAlgorithmIdentifier = pkix.AlgorithmIdentifier{
|
||||
Algorithm: e.EncryptionAlgorithmIdentifier,
|
||||
Parameters: asn1.RawValue{Tag: 4, Bytes: e.IV}}
|
||||
case EncryptionAlgorithmAES128GCM.String():
|
||||
aead, err = cipher.NewGCM(blockCipher)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case AEADChaCha20Poly1305.String():
|
||||
aead, err = chacha20poly1305.New(e.Key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String():
|
||||
var plain []byte
|
||||
plain, err = pad(plaintext, blockCipher.BlockSize())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ciphertext = make([]byte, len(plain))
|
||||
|
||||
blockMode.CryptBlocks(ciphertext, plain)
|
||||
|
||||
return
|
||||
case EncryptionAlgorithmAES128GCM.String(), AEADChaCha20Poly1305.String():
|
||||
nonce := make([]byte, nonceSize)
|
||||
_, err = rand.Read(nonce)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ciphertext = aead.Seal(nil, nonce, plaintext, nil)
|
||||
|
||||
e.MAC = ciphertext[len(ciphertext)-aead.Overhead():]
|
||||
ciphertext = ciphertext[:len(ciphertext)-aead.Overhead()]
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128GCM.String():
|
||||
paramSeq := aesGCMParameters{
|
||||
Nonce: nonce,
|
||||
ICVLen: aead.Overhead(),
|
||||
}
|
||||
|
||||
paramBytes, _ := asn1.Marshal(paramSeq)
|
||||
|
||||
e.ContentEncryptionAlgorithmIdentifier = pkix.AlgorithmIdentifier{
|
||||
Algorithm: e.EncryptionAlgorithmIdentifier,
|
||||
Parameters: asn1.RawValue{
|
||||
Tag: asn1.TagSequence,
|
||||
Bytes: paramBytes,
|
||||
}}
|
||||
case AEADChaCha20Poly1305.String():
|
||||
e.ContentEncryptionAlgorithmIdentifier = pkix.AlgorithmIdentifier{
|
||||
Algorithm: e.EncryptionAlgorithmIdentifier,
|
||||
Parameters: asn1.RawValue{Tag: 4, Bytes: nonce}}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const nonceSize = 12
|
||||
|
||||
type aesGCMParameters struct {
|
||||
Nonce []byte `asn1:"tag:4"`
|
||||
ICVLen int
|
||||
}
|
||||
|
||||
// Decrypt decrypts the ciphertext and returns the plaintext.
|
||||
func (e *EncryptionAlgorithm) Decrypt(ciphertext []byte) (plaintext []byte, err error) {
|
||||
|
||||
e.EncryptionAlgorithmIdentifier = e.ContentEncryptionAlgorithmIdentifier.Algorithm
|
||||
|
||||
//Choose cipher
|
||||
var blockCipher cipher.Block
|
||||
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String(), EncryptionAlgorithmAES128GCM.String():
|
||||
blockCipher, err = aes.NewCipher(e.Key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case EncryptionAlgorithmDESCBC.String():
|
||||
blockCipher, err = des.NewCipher(e.Key)
|
||||
fmt.Println("Warning: message is encoded with DES. DES should NOT be used.")
|
||||
case EncryptionAlgorithmDESEDE3CBC.String():
|
||||
blockCipher, err = des.NewTripleDESCipher(e.Key)
|
||||
fmt.Println("Warning: message is encoded with 3DES. 3DES should NOT be used.")
|
||||
case AEADChaCha20Poly1305.String():
|
||||
default:
|
||||
err = errors.New("Content encrytion: cipher not supportet")
|
||||
return
|
||||
}
|
||||
|
||||
//Choose blockmode
|
||||
var blockMode cipher.BlockMode
|
||||
var aead cipher.AEAD
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String(), EncryptionAlgorithmDESCBC.String(), EncryptionAlgorithmDESEDE3CBC.String():
|
||||
e.IV = e.ContentEncryptionAlgorithmIdentifier.Parameters.Bytes
|
||||
|
||||
blockMode = cipher.NewCBCDecrypter(blockCipher, e.IV)
|
||||
case EncryptionAlgorithmAES128GCM.String():
|
||||
aead, err = cipher.NewGCM(blockCipher)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case AEADChaCha20Poly1305.String():
|
||||
aead, err = chacha20poly1305.New(e.Key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String(), EncryptionAlgorithmDESCBC.String(), EncryptionAlgorithmDESEDE3CBC.String():
|
||||
plaintext = make([]byte, len(ciphertext))
|
||||
blockMode.CryptBlocks(plaintext, ciphertext)
|
||||
|
||||
return unpad(plaintext, blockMode.BlockSize())
|
||||
case EncryptionAlgorithmAES128GCM.String(), AEADChaCha20Poly1305.String():
|
||||
var cipher []byte
|
||||
cipher = append(cipher, ciphertext...)
|
||||
cipher = append(cipher, e.MAC...)
|
||||
|
||||
var nonce []byte
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128GCM.String():
|
||||
params := aesGCMParameters{}
|
||||
paramBytes := e.ContentEncryptionAlgorithmIdentifier.Parameters.Bytes
|
||||
_, err = asn1.Unmarshal(paramBytes, ¶ms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nonce = params.Nonce
|
||||
case AEADChaCha20Poly1305.String():
|
||||
nonce = e.ContentEncryptionAlgorithmIdentifier.Parameters.Bytes
|
||||
}
|
||||
|
||||
plaintext, err = aead.Open(nil, nonce, cipher, nil)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func pad(data []byte, blocklen int) ([]byte, error) {
|
||||
if blocklen < 1 {
|
||||
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
||||
}
|
||||
padlen := blocklen - (len(data) % blocklen)
|
||||
if padlen == 0 {
|
||||
padlen = blocklen
|
||||
}
|
||||
pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
|
||||
return append(data, pad...), nil
|
||||
}
|
||||
|
||||
func unpad(data []byte, blocklen int) ([]byte, error) {
|
||||
if blocklen < 1 {
|
||||
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
||||
}
|
||||
if len(data)%blocklen != 0 || len(data) == 0 {
|
||||
return nil, fmt.Errorf("invalid data len %d", len(data))
|
||||
}
|
||||
|
||||
// the last byte is the length of padding
|
||||
padlen := int(data[len(data)-1])
|
||||
|
||||
// check padding integrity, all bytes should be the same
|
||||
pad := data[len(data)-padlen:]
|
||||
for _, padbyte := range pad {
|
||||
if padbyte != byte(padlen) {
|
||||
return nil, errors.New("invalid padding")
|
||||
}
|
||||
}
|
||||
|
||||
return data[:len(data)-padlen], nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user