mirror of
https://github.com/gregtwallace/apc-p15-tool.git
synced 2025-01-22 08:14:08 +00:00
add some KEK and CEK functions
This commit is contained in:
parent
2dd129c60a
commit
6610c92058
4 changed files with 122 additions and 0 deletions
94
cek.go
Normal file
94
cek.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// decryptCEK decrypts the encrypted CEK and unwraps the CEK so only the
|
||||
// original CEK is returned
|
||||
func decryptCEK(encryptedCEK, encryptedCekSalt, KEK []byte) (CEK []byte, err error) {
|
||||
// ensure proper var lens, or error
|
||||
encryptedCEKLen := 24
|
||||
CEKSaltLen := 8
|
||||
KEKLen := 24
|
||||
|
||||
if len(encryptedCEK) != encryptedCEKLen {
|
||||
return nil, errors.New("wrong encrypted CEK length")
|
||||
}
|
||||
if len(encryptedCekSalt) != CEKSaltLen {
|
||||
return nil, errors.New("wrong encrypted CEK's salt length")
|
||||
}
|
||||
if len(KEK) != KEKLen {
|
||||
return nil, errors.New("wrong KEK length")
|
||||
}
|
||||
|
||||
// 3DES uses block byte size of 8
|
||||
blockByteSize := 8
|
||||
|
||||
// make DES cipher from KEK
|
||||
kekDesCipher, err := des.NewTripleDESCipher(KEK)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to make DES cipher for cek decryption (%s)", err)
|
||||
}
|
||||
|
||||
// (1) first use n-1'th block as IV to decrypt n'th block
|
||||
ivStart := encryptedCEKLen - 2*blockByteSize
|
||||
ivEnd := encryptedCEKLen - 1*blockByteSize
|
||||
|
||||
ivBlockCipherText := encryptedCEK[ivStart:ivEnd]
|
||||
nthBlockCipherText := encryptedCEK[encryptedCEKLen-1*blockByteSize:]
|
||||
|
||||
firstBlockDecrypter := cipher.NewCBCDecrypter(kekDesCipher, ivBlockCipherText)
|
||||
|
||||
decryptedNthBlock := make([]byte, len(nthBlockCipherText))
|
||||
firstBlockDecrypter.CryptBlocks(decryptedNthBlock, nthBlockCipherText)
|
||||
|
||||
// (2) decrypt remainder of outer encryption blocks (1 ... n-1'th) using
|
||||
// the decrypted nthBlock as the IV
|
||||
outerRemainderDecrypter := cipher.NewCBCDecrypter(kekDesCipher, decryptedNthBlock)
|
||||
|
||||
decryptedOuterRemainder := make([]byte, encryptedCEKLen-1*blockByteSize)
|
||||
outerRemainderDecrypter.CryptBlocks(decryptedOuterRemainder, encryptedCEK[:encryptedCEKLen-1*blockByteSize])
|
||||
|
||||
// combine decrypted remainder with decrypted nth block for complete decrypted bytes
|
||||
// this is equivelant to having the outer encryption removed, AKA the CEK is encrypted
|
||||
// once now instead of twice
|
||||
onceEncryptedCEK := append(decryptedOuterRemainder, decryptedNthBlock...)
|
||||
|
||||
// (3) Decrypted the inner layer of encryption using the KEK (aka decrypt the remaining
|
||||
// layer of encryption)
|
||||
|
||||
// inner decrypter uses original CEK salt
|
||||
innerDecrypter := cipher.NewCBCDecrypter(kekDesCipher, encryptedCekSalt)
|
||||
|
||||
// once decrypted, the CEK is still formatted as:
|
||||
// CEK byte count || check value || CEK || padding (if required)
|
||||
formattedCEK := make([]byte, len(onceEncryptedCEK))
|
||||
innerDecrypter.CryptBlocks(formattedCEK, onceEncryptedCEK)
|
||||
|
||||
// Now that CEK is decrypted, sanity check it
|
||||
|
||||
// first byte is CEK byte count
|
||||
expectedCEKLen := formattedCEK[0]
|
||||
|
||||
// (1a) expected cek len must be 16 or 24 or 3DES (which is what APC uses)
|
||||
if int(expectedCEKLen) != 16 && int(expectedCEKLen) != 24 {
|
||||
return nil, errors.New("expected CEK len block size is %d but 3DES requires 16 or 24 (decrypting likely failed)")
|
||||
}
|
||||
|
||||
// next 3 bytes are the check value
|
||||
CEKCheckVal := formattedCEK[1:4]
|
||||
|
||||
// CEK itself is the next bytes until CEK is the expected length
|
||||
CEK = formattedCEK[4 : expectedCEKLen+4]
|
||||
|
||||
// (1b) key check data validation
|
||||
if !isBitwiseCompliment(CEKCheckVal, CEK[0:3]) {
|
||||
return nil, errors.New("CEK check value did not match CEK")
|
||||
}
|
||||
|
||||
return CEK, nil
|
||||
}
|
2
go.mod
2
go.mod
|
@ -3,3 +3,5 @@ module temp
|
|||
go 1.21
|
||||
|
||||
require github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||
|
||||
require golang.org/x/crypto v0.18.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1,2 +1,4 @@
|
|||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
|
|
24
kek.go
Normal file
24
kek.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
// makeKEK creates the APC KEK for a given Salt; APC uses a fixed
|
||||
// password, iteration count, and hash function
|
||||
func makeKEK(salt []byte) (KEK []byte) {
|
||||
// password is known constant for APC files
|
||||
password := "user"
|
||||
|
||||
// fixed values for APC files
|
||||
iterations := 5000
|
||||
hash := sha256.New
|
||||
|
||||
// size of 3DES key (k1 + k2 + k3)
|
||||
size := 24
|
||||
|
||||
// kek
|
||||
return pbkdf2.Key([]byte(password), salt, iterations, size, hash)
|
||||
}
|
Loading…
Reference in a new issue