Created
October 3, 2023 15:44
-
-
Save wader/bcbc9302fe1a3040834feddd227bc20f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// usage: | |
// cat BK7231T_TuyaConfig_obk8D7EC082.bin | go run tyuaconfig.go > out | |
package main | |
import ( | |
"crypto/aes" | |
"crypto/cipher" | |
"io" | |
"log" | |
"os" | |
) | |
// from https://github.com/openshwprojects/BK7231GUIFlashTool/blob/5c6ff0551bb0529f8917653f7adb9f49ccaf43c8/BK7231Flasher/TuyaConfig.cs | |
// // thanks to kmnh & Kuba bk7231 tools for figuring out this format | |
// static string KEY_MASTER = "qwertyuiopasdfgh"; | |
// static int SECTOR_SIZE = 4096; | |
// static uint MAGIC_FIRST_BLOCK = 0x13579753; | |
// static uint MAGIC_NEXT_BLOCK = 0x98761234; | |
// static byte[] KEY_PART_1 = Encoding.ASCII.GetBytes("8710_2M"); | |
// static byte[] KEY_PART_2 = Encoding.ASCII.GetBytes("HHRRQbyemofrtytf"); | |
// static byte[] MAGIC_CONFIG_START = new byte[] { 0x46, 0xDC, 0xED, 0x0E, 0x67, 0x2F, 0x3B, 0x70, 0xAE, 0x12, 0x76, 0xA3, 0xF8, 0x71, 0x2E, 0x03 }; | |
// // TODO: check more bins with this offset | |
// // hex 0x1EE000 | |
// // While flash is 0x200000, so we have at most 0x12000 bytes there... | |
// // So it's 0x12 sectors (18 sectors) | |
// byte[] makeSecondaryKey(byte[] innerKey) | |
// { | |
// byte[] key = new byte[0x10]; | |
// for (int i = 0; i < 16; i++) | |
// { | |
// key[i] = (byte)(KEY_PART_1[i & 3] + KEY_PART_2[i]); | |
// } | |
// for (int i = 0; i < 16; i++) | |
// { | |
// key[i] = (byte)((key[i] + innerKey[i]) % 256); | |
// } | |
// return key; | |
// } | |
func makeSecondaryKey(innerKey []byte) []byte { | |
var key [0x10]byte | |
for i := 0; i < 16; i++ { | |
key[i] = (byte)(KEY_PART_1[i&3] + KEY_PART_2[i]) | |
} | |
for i := 0; i < 16; i++ { | |
key[i] = (byte)((key[i] + innerKey[i]) /*% 256*/) | |
} | |
return key[:] | |
} | |
var KEY_MASTER = []byte("qwertyuiopasdfgh") | |
const SECTOR_SIZE = 4096 | |
var KEY_PART_1 = []byte("8710_2M") | |
var KEY_PART_2 = []byte("HHRRQbyemofrtytf") | |
// from https://github.com/andreburgaud/crypt2go/blob/v1.4.0/ecb/ecb.go | |
type ecb struct { | |
b cipher.Block | |
blockSize int | |
tmp []byte | |
} | |
func newECB(b cipher.Block) *ecb { | |
return &ecb{ | |
b: b, | |
blockSize: b.BlockSize(), | |
tmp: make([]byte, b.BlockSize()), | |
} | |
} | |
type ecbDecrypter ecb | |
// NewECBDecrypter returns a BlockMode which decrypts in electronic codebook (ECB) | |
// mode, using the given Block. | |
func NewECBDecrypter(b cipher.Block) cipher.BlockMode { | |
return (*ecbDecrypter)(newECB(b)) | |
} | |
func (x *ecbDecrypter) BlockSize() int { return x.blockSize } | |
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) { | |
if len(src)%x.blockSize != 0 { | |
panic("crypto/cipher: input not full blocks") | |
} | |
if len(dst) < len(src) { | |
panic("crypto/cipher: output smaller than input") | |
} | |
if len(src) == 0 { | |
return | |
} | |
for len(src) > 0 { | |
x.b.Decrypt(dst[:x.blockSize], src[:x.blockSize]) | |
src = src[x.blockSize:] | |
dst = dst[x.blockSize:] | |
} | |
} | |
func main() { | |
log.Println("bla") | |
inputEncrypted, err := io.ReadAll(os.Stdin) | |
if err != nil { | |
panic(err) | |
} | |
cb, err := aes.NewCipher(KEY_MASTER) | |
if err != nil { | |
panic(err) | |
} | |
headerSectorPlain := [SECTOR_SIZE]byte{} | |
cm := NewECBDecrypter(cb) | |
cm.CryptBlocks(headerSectorPlain[:], inputEncrypted[0:SECTOR_SIZE]) | |
//os.Stdout.Write(headerSectorPlain[:]) | |
const MAGIC_SIZE = 4 | |
const CRC_SIZE = 4 | |
key := headerSectorPlain[MAGIC_SIZE+CRC_SIZE : MAGIC_SIZE+CRC_SIZE+16] | |
secondaryKey := makeSecondaryKey(key) | |
secondaryCB, err := aes.NewCipher(secondaryKey) | |
if err != nil { | |
panic(err) | |
} | |
sectorPlain := [SECTOR_SIZE]byte{} | |
secondaryCM := NewECBDecrypter(secondaryCB) | |
for sectorIndex := 1; (sectorIndex+1)*SECTOR_SIZE < len(inputEncrypted); sectorIndex++ { | |
secondaryCM.CryptBlocks(sectorPlain[:], inputEncrypted[sectorIndex*SECTOR_SIZE:(sectorIndex+1)*SECTOR_SIZE]) | |
os.Stdout.Write(sectorPlain[MAGIC_SIZE+CRC_SIZE:]) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment