1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
package ipmi
import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/md5"
"crypto/rc4"
"crypto/sha1"
"crypto/sha256"
"fmt"
)
// generate_hmac generates message authentication code.
// Currently supported algorithms are: "md5", "sha1", "sha256"
//
// hmac, hash-based message authentication code
// mac, message authentication code
// md, message digest
func generate_hmac(alg string, data []byte, key []byte) ([]byte, error) {
switch alg {
case "md5":
h := hmac.New(md5.New, key)
_, err := h.Write(data)
if err != nil {
return nil, fmt.Errorf("hmac md5 failed, err: %w", err)
}
return h.Sum(nil), nil
case "sha1":
h := hmac.New(sha1.New, key)
_, err := h.Write(data)
if err != nil {
return nil, fmt.Errorf("hmac sha1 failed, err: %w", err)
}
return h.Sum(nil), nil
case "sha256":
h := hmac.New(sha256.New, key)
_, err := h.Write(data)
if err != nil {
return nil, fmt.Errorf("hmac sha256 failed, err: %w", err)
}
return h.Sum(nil), nil
default:
return nil, fmt.Errorf("not support for hmac algorithm %s", alg)
}
}
func generate_auth_hmac(authAlg interface{}, data []byte, key []byte) ([]byte, error) {
algorithm := ""
switch authAlg.(type) {
case AuthAlg:
switch authAlg {
case AuthAlgRAKP_HMAC_SHA1:
algorithm = "sha1"
case AuthAlgRAKP_HMAC_MD5:
algorithm = "md5"
case AuthAlgRAKP_HMAC_SHA256:
algorithm = "sha256"
default:
return nil, fmt.Errorf("not support for authentication algorithm %x", authAlg)
}
case IntegrityAlg:
switch authAlg {
case IntegrityAlg_HMAC_SHA1_96:
algorithm = "sha1"
case IntegrityAlg_HMAC_MD5_128:
algorithm = "md5"
case IntegrityAlg_HMAC_SHA256_128:
algorithm = "sha256"
default:
return nil, fmt.Errorf("not support for integrity algorithm %x", authAlg)
}
}
if len(algorithm) == 0 {
return []byte{}, nil
} else {
return generate_hmac(algorithm, data, key)
}
}
// The plainText must be already padded.
// The cipherKey length is either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func encryptAES(plainText []byte, cipherKey []byte, iv []byte) ([]byte, error) {
if len(plainText)%aes.BlockSize != 0 {
return nil, fmt.Errorf("input plainText must be multiple of aes block size (16)")
}
l := len(cipherKey)
if l != 16 && l != 24 && l != 32 {
return nil, fmt.Errorf("cipherKey length must be either 16, 24, 32")
}
cipherBlock, err := aes.NewCipher(cipherKey)
if err != nil {
return nil, fmt.Errorf("NewCipher failed, err: %w", err)
}
cipherText := make([]byte, len(plainText))
mode := cipher.NewCBCEncrypter(cipherBlock, iv)
mode.CryptBlocks(cipherText, plainText)
return cipherText, nil
}
func decryptAES(cipherText []byte, cipherKey []byte, iv []byte) ([]byte, error) {
l := len(cipherKey)
if l != 16 && l != 24 && l != 32 {
return nil, fmt.Errorf("cipherKey length must be either 16, 24, 32")
}
cipherBlock, err := aes.NewCipher(cipherKey)
if err != nil {
return nil, fmt.Errorf("NewCipher failed, err: %w", err)
}
plainText := make([]byte, len(cipherText))
mode := cipher.NewCBCDecrypter(cipherBlock, iv)
mode.CryptBlocks(plainText, cipherText)
return plainText, nil
}
func encryptRC4(plainText []byte, cipherKey []byte, iv []byte) ([]byte, error) {
rc4Cipher, err := rc4.NewCipher(cipherKey)
if err != nil {
return nil, fmt.Errorf("NewCipher failed, err: %w", err)
}
cipherText := make([]byte, len(plainText))
rc4Cipher.XORKeyStream(cipherText, plainText)
return cipherText, nil
}
func decryptRC4(cipherText []byte, cipherKey []byte, iv []byte) ([]byte, error) {
rc4Cipher, err := rc4.NewCipher(cipherKey)
if err != nil {
return nil, fmt.Errorf("NewCipher failed, err: %w", err)
}
plainText := make([]byte, len(cipherText))
rc4Cipher.XORKeyStream(plainText, cipherText)
return plainText, nil
}
|