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
|
go 1.21
|
||||||
|
|
||||||
require github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
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 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
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