keycard-go/globalplatform/crypto/crypto.go

148 lines
3.6 KiB
Go
Raw Normal View History

2018-09-27 09:26:21 +00:00
package crypto
import (
2018-09-27 10:08:29 +00:00
"bytes"
2018-09-27 09:26:21 +00:00
"crypto/cipher"
/* #nosec */
2018-09-27 09:26:21 +00:00
"crypto/des"
)
var (
2018-10-05 14:40:32 +00:00
// DerivationPurposeEnc defines 2 bytes used when deriving a encoding key.
2018-09-27 09:26:21 +00:00
DerivationPurposeEnc = []byte{0x01, 0x82}
2018-10-05 14:40:32 +00:00
// DerivationPurposeMac defines 2 bytes used when deriving a mac key.
2018-09-27 13:29:07 +00:00
DerivationPurposeMac = []byte{0x01, 0x01}
2018-10-05 14:40:32 +00:00
// NullBytes8 defined a slice of 8 zero bytes mostrly used as IV in cryptographic functions.
NullBytes8 = []byte{0, 0, 0, 0, 0, 0, 0, 0}
2018-09-27 09:26:21 +00:00
)
2018-10-05 14:40:32 +00:00
// DeriveKey derives a key from the current cardKey using the sequence number receive from the card and the purpose (ENC/MAC).
2018-09-27 09:26:21 +00:00
func DeriveKey(cardKey []byte, seq []byte, purpose []byte) ([]byte, error) {
key24 := resizeKey24(cardKey)
derivation := make([]byte, 16)
copy(derivation, purpose[:2])
copy(derivation[2:], seq[:2])
/* #nosec */
2018-09-27 09:26:21 +00:00
block, err := des.NewTripleDESCipher(key24)
if err != nil {
return nil, err
}
ciphertext := make([]byte, 16)
2018-09-27 16:01:09 +00:00
mode := cipher.NewCBCEncrypter(block, NullBytes8)
2018-09-27 09:26:21 +00:00
mode.CryptBlocks(ciphertext, derivation)
return ciphertext, nil
}
2018-10-05 14:40:32 +00:00
// VerifyCryptogram verifies the cryptogram sends from the card to ensure that card and client are using the same keys to communicate.
2018-09-27 10:08:29 +00:00
func VerifyCryptogram(encKey, hostChallenge, cardChallenge, cardCryptogram []byte) (bool, error) {
data := make([]byte, 0)
data = append(data, hostChallenge...)
data = append(data, cardChallenge...)
2018-10-01 11:25:24 +00:00
paddedData := AppendDESPadding(data)
calculated, err := Mac3DES(encKey, paddedData, NullBytes8)
2018-09-27 10:08:29 +00:00
if err != nil {
return false, err
}
return bytes.Equal(calculated, cardCryptogram), nil
}
2018-10-05 14:40:32 +00:00
// MacFull3DES generates a full triple DES mac.
2018-09-27 11:19:19 +00:00
func MacFull3DES(key, data, iv []byte) ([]byte, error) {
2018-10-01 11:25:24 +00:00
data = AppendDESPadding(data)
2018-09-27 11:19:19 +00:00
/* #nosec */
2018-09-27 11:19:19 +00:00
desBlock, err := des.NewCipher(resizeKey8(key))
if err != nil {
return nil, err
}
/* #nosec */
2018-09-27 11:19:19 +00:00
des3Block, err := des.NewTripleDESCipher(resizeKey24(key))
if err != nil {
return nil, err
}
des3IV := iv
if len(data) > 8 {
length := len(data) - 8
tmp := make([]byte, length)
mode := cipher.NewCBCEncrypter(desBlock, iv)
mode.CryptBlocks(tmp, data[:length])
2018-10-02 13:52:12 +00:00
des3IV = tmp[length-8:]
2018-09-27 11:19:19 +00:00
}
ciphertext := make([]byte, 8)
mode := cipher.NewCBCEncrypter(des3Block, des3IV)
mode.CryptBlocks(ciphertext, data[len(data)-8:])
return ciphertext, nil
}
2018-10-05 14:40:32 +00:00
// EncryptICV encrypts an ICV with the specified macKey.
// The ICV is usually the mac of the previous command sent in the current session.
func EncryptICV(macKey, icv []byte) ([]byte, error) {
/* #nosec */
2018-09-27 16:01:09 +00:00
block, err := des.NewCipher(resizeKey8(macKey))
if err != nil {
return nil, err
}
2018-09-28 09:25:08 +00:00
ciphertext := make([]byte, 8)
2018-09-27 16:01:09 +00:00
mode := cipher.NewCBCEncrypter(block, NullBytes8)
2018-10-05 14:40:32 +00:00
mode.CryptBlocks(ciphertext, icv)
2018-09-27 16:01:09 +00:00
return ciphertext, nil
}
2018-10-05 14:40:32 +00:00
// Mac3DES generates the triple DES mac of data using the specified key and icv.
2018-10-01 11:25:24 +00:00
func Mac3DES(key, data, iv []byte) ([]byte, error) {
2018-09-27 10:08:29 +00:00
key24 := resizeKey24(key)
/* #nosec */
2018-09-27 10:08:29 +00:00
block, err := des.NewTripleDESCipher(key24)
if err != nil {
return nil, err
}
ciphertext := make([]byte, 24)
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, data)
return ciphertext[16:], nil
}
2018-10-05 14:40:32 +00:00
// AppendDESPadding appends an 0x80 bytes to data and other zero bytes to make the result length multiple of 8.
2018-10-01 11:25:24 +00:00
func AppendDESPadding(data []byte) []byte {
2018-09-27 09:39:35 +00:00
length := len(data) + 1
for ; length%8 != 0; length++ {
}
newData := make([]byte, length)
copy(newData, data)
copy(newData[len(data):], []byte{0x80})
return newData
}
2018-10-05 14:40:32 +00:00
func resizeKey24(key []byte) []byte {
data := make([]byte, 24)
copy(data, key[0:16])
copy(data[16:], key[0:8])
return data
}
func resizeKey8(key []byte) []byte {
return key[:8]
}