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:
InfiniteLoopSpace 2018-11-15 12:29:43 +01:00
parent b33189be9c
commit 9179582f90
2 changed files with 389 additions and 0 deletions

129
oid/oid.go Normal file
View 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
View 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, &params)
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
}