package crypto
import (
"encoding/hex"
"fmt"
"github.com/jcmturner/gokrb5/v8/crypto/etype"
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
"github.com/jcmturner/gokrb5/v8/iana/patype"
"github.com/jcmturner/gokrb5/v8/types"
)
func GetEtype (id int32 ) (etype .EType , error ) {
switch id {
case etypeID .AES128_CTS_HMAC_SHA1_96 :
var et Aes128CtsHmacSha96
return et , nil
case etypeID .AES256_CTS_HMAC_SHA1_96 :
var et Aes256CtsHmacSha96
return et , nil
case etypeID .AES128_CTS_HMAC_SHA256_128 :
var et Aes128CtsHmacSha256128
return et , nil
case etypeID .AES256_CTS_HMAC_SHA384_192 :
var et Aes256CtsHmacSha384192
return et , nil
case etypeID .DES3_CBC_SHA1_KD :
var et Des3CbcSha1Kd
return et , nil
case etypeID .RC4_HMAC :
var et RC4HMAC
return et , nil
default :
return nil , fmt .Errorf ("unknown or unsupported EType: %d" , id )
}
}
func GetChksumEtype (id int32 ) (etype .EType , error ) {
switch id {
case chksumtype .HMAC_SHA1_96_AES128 :
var et Aes128CtsHmacSha96
return et , nil
case chksumtype .HMAC_SHA1_96_AES256 :
var et Aes256CtsHmacSha96
return et , nil
case chksumtype .HMAC_SHA256_128_AES128 :
var et Aes128CtsHmacSha256128
return et , nil
case chksumtype .HMAC_SHA384_192_AES256 :
var et Aes256CtsHmacSha384192
return et , nil
case chksumtype .HMAC_SHA1_DES3_KD :
var et Des3CbcSha1Kd
return et , nil
case chksumtype .KERB_CHECKSUM_HMAC_MD5 :
var et RC4HMAC
return et , nil
default :
return nil , fmt .Errorf ("unknown or unsupported checksum type: %d" , id )
}
}
func GetKeyFromPassword (passwd string , cname types .PrincipalName , realm string , etypeID int32 , pas types .PADataSequence ) (types .EncryptionKey , etype .EType , error ) {
var key types .EncryptionKey
et , err := GetEtype (etypeID )
if err != nil {
return key , et , fmt .Errorf ("error getting encryption type: %v" , err )
}
sk2p := et .GetDefaultStringToKeyParams ()
var salt string
var paID int32
for _ , pa := range pas {
switch pa .PADataType {
case patype .PA_PW_SALT :
if paID > pa .PADataType {
continue
}
salt = string (pa .PADataValue )
case patype .PA_ETYPE_INFO :
if paID > pa .PADataType {
continue
}
var eti types .ETypeInfo
err := eti .Unmarshal (pa .PADataValue )
if err != nil {
return key , et , fmt .Errorf ("error unmashaling PA Data to PA-ETYPE-INFO2: %v" , err )
}
if etypeID != eti [0 ].EType {
et , err = GetEtype (eti [0 ].EType )
if err != nil {
return key , et , fmt .Errorf ("error getting encryption type: %v" , err )
}
}
salt = string (eti [0 ].Salt )
case patype .PA_ETYPE_INFO2 :
if paID > pa .PADataType {
continue
}
var et2 types .ETypeInfo2
err := et2 .Unmarshal (pa .PADataValue )
if err != nil {
return key , et , fmt .Errorf ("error unmashalling PA Data to PA-ETYPE-INFO2: %v" , err )
}
if etypeID != et2 [0 ].EType {
et , err = GetEtype (et2 [0 ].EType )
if err != nil {
return key , et , fmt .Errorf ("error getting encryption type: %v" , err )
}
}
if len (et2 [0 ].S2KParams ) == 4 {
sk2p = hex .EncodeToString (et2 [0 ].S2KParams )
}
salt = et2 [0 ].Salt
}
}
if salt == "" {
salt = cname .GetSalt (realm )
}
k , err := et .StringToKey (passwd , salt , sk2p )
if err != nil {
return key , et , fmt .Errorf ("error deriving key from string: %+v" , err )
}
key = types .EncryptionKey {
KeyType : etypeID ,
KeyValue : k ,
}
return key , et , nil
}
func GetEncryptedData (plainBytes []byte , key types .EncryptionKey , usage uint32 , kvno int ) (types .EncryptedData , error ) {
var ed types .EncryptedData
et , err := GetEtype (key .KeyType )
if err != nil {
return ed , fmt .Errorf ("error getting etype: %v" , err )
}
_ , b , err := et .EncryptMessage (key .KeyValue , plainBytes , usage )
if err != nil {
return ed , err
}
ed = types .EncryptedData {
EType : key .KeyType ,
Cipher : b ,
KVNO : kvno ,
}
return ed , nil
}
func DecryptEncPart (ed types .EncryptedData , key types .EncryptionKey , usage uint32 ) ([]byte , error ) {
return DecryptMessage (ed .Cipher , key , usage )
}
func DecryptMessage (ciphertext []byte , key types .EncryptionKey , usage uint32 ) ([]byte , error ) {
et , err := GetEtype (key .KeyType )
if err != nil {
return []byte {}, fmt .Errorf ("error decrypting: %v" , err )
}
b , err := et .DecryptMessage (key .KeyValue , ciphertext , usage )
if err != nil {
return nil , fmt .Errorf ("error decrypting: %v" , err )
}
return b , nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .