201 lines
9.7 KiB
Swift
201 lines
9.7 KiB
Swift
import Foundation
|
|
import CryptoSwift
|
|
|
|
public struct CdkeyDecodeAlpha26 {
|
|
|
|
static let KeyTable: [UInt8] = [
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0x00, 0xFF, 0x01, 0xFF, 0x02, 0x03, 0x04, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0x0D, 0x0E, 0xFF, 0x0F, 0x10, 0xFF,
|
|
0x11, 0xFF, 0x12, 0xFF, 0x13, 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0x0D, 0x0E, 0xFF, 0x0F, 0x10, 0xFF,
|
|
0x11, 0xFF, 0x12, 0xFF, 0x13, 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
|
]
|
|
|
|
static let TranslateTable: [UInt8] = [
|
|
0x09, 0x04, 0x07, 0x0F, 0x0D, 0x0A, 0x03, 0x0B, 0x01, 0x02, 0x0C, 0x08, 0x06, 0x0E, 0x05, 0x00,
|
|
0x09, 0x0B, 0x05, 0x04, 0x08, 0x0F, 0x01, 0x0E, 0x07, 0x00, 0x03, 0x02, 0x0A, 0x06, 0x0D, 0x0C,
|
|
0x0C, 0x0E, 0x01, 0x04, 0x09, 0x0F, 0x0A, 0x0B, 0x0D, 0x06, 0x00, 0x08, 0x07, 0x02, 0x05, 0x03,
|
|
0x0B, 0x02, 0x05, 0x0E, 0x0D, 0x03, 0x09, 0x00, 0x01, 0x0F, 0x07, 0x0C, 0x0A, 0x06, 0x04, 0x08,
|
|
0x06, 0x02, 0x04, 0x05, 0x0B, 0x08, 0x0C, 0x0E, 0x0D, 0x0F, 0x07, 0x01, 0x0A, 0x00, 0x03, 0x09,
|
|
0x05, 0x04, 0x0E, 0x0C, 0x07, 0x06, 0x0D, 0x0A, 0x0F, 0x02, 0x09, 0x01, 0x00, 0x0B, 0x08, 0x03,
|
|
0x0C, 0x07, 0x08, 0x0F, 0x0B, 0x00, 0x05, 0x09, 0x0D, 0x0A, 0x06, 0x0E, 0x02, 0x04, 0x03, 0x01,
|
|
0x03, 0x0A, 0x0E, 0x08, 0x01, 0x0B, 0x05, 0x04, 0x02, 0x0F, 0x0D, 0x0C, 0x06, 0x07, 0x09, 0x00,
|
|
0x0C, 0x0D, 0x01, 0x0F, 0x08, 0x0E, 0x05, 0x0B, 0x03, 0x0A, 0x09, 0x00, 0x07, 0x02, 0x04, 0x06,
|
|
0x0D, 0x0A, 0x07, 0x0E, 0x01, 0x06, 0x0B, 0x08, 0x0F, 0x0C, 0x05, 0x02, 0x03, 0x00, 0x04, 0x09,
|
|
0x03, 0x0E, 0x07, 0x05, 0x0B, 0x0F, 0x08, 0x0C, 0x01, 0x0A, 0x04, 0x0D, 0x00, 0x06, 0x09, 0x02,
|
|
0x0B, 0x06, 0x09, 0x04, 0x01, 0x08, 0x0A, 0x0D, 0x07, 0x0E, 0x00, 0x0C, 0x0F, 0x02, 0x03, 0x05,
|
|
0x0C, 0x07, 0x08, 0x0D, 0x03, 0x0B, 0x00, 0x0E, 0x06, 0x0F, 0x09, 0x04, 0x0A, 0x01, 0x05, 0x02,
|
|
0x0C, 0x06, 0x0D, 0x09, 0x0B, 0x00, 0x01, 0x02, 0x0F, 0x07, 0x03, 0x04, 0x0A, 0x0E, 0x08, 0x05,
|
|
0x03, 0x06, 0x01, 0x05, 0x0B, 0x0C, 0x08, 0x00, 0x0F, 0x0E, 0x09, 0x04, 0x07, 0x0A, 0x0D, 0x02,
|
|
0x0A, 0x07, 0x0B, 0x0F, 0x02, 0x08, 0x00, 0x0D, 0x0E, 0x0C, 0x01, 0x06, 0x09, 0x03, 0x05, 0x04,
|
|
0x0A, 0x0B, 0x0D, 0x04, 0x03, 0x08, 0x05, 0x09, 0x01, 0x00, 0x0F, 0x0C, 0x07, 0x0E, 0x02, 0x06,
|
|
0x0B, 0x04, 0x0D, 0x0F, 0x01, 0x06, 0x03, 0x0E, 0x07, 0x0A, 0x0C, 0x08, 0x09, 0x02, 0x05, 0x00,
|
|
0x09, 0x06, 0x07, 0x00, 0x01, 0x0A, 0x0D, 0x02, 0x03, 0x0E, 0x0F, 0x0C, 0x05, 0x0B, 0x04, 0x08,
|
|
0x0D, 0x0E, 0x05, 0x06, 0x01, 0x09, 0x08, 0x0C, 0x02, 0x0F, 0x03, 0x07, 0x0B, 0x04, 0x00, 0x0A,
|
|
0x09, 0x0F, 0x04, 0x00, 0x01, 0x06, 0x0A, 0x0E, 0x02, 0x03, 0x07, 0x0D, 0x05, 0x0B, 0x08, 0x0C,
|
|
0x03, 0x0E, 0x01, 0x0A, 0x02, 0x0C, 0x08, 0x04, 0x0B, 0x07, 0x0D, 0x00, 0x0F, 0x06, 0x09, 0x05,
|
|
0x07, 0x02, 0x0C, 0x06, 0x0A, 0x08, 0x0B, 0x00, 0x0F, 0x04, 0x03, 0x0E, 0x09, 0x01, 0x0D, 0x05,
|
|
0x0C, 0x04, 0x05, 0x09, 0x0A, 0x02, 0x08, 0x0D, 0x03, 0x0F, 0x01, 0x0E, 0x06, 0x07, 0x0B, 0x00,
|
|
0x0A, 0x08, 0x0E, 0x0D, 0x09, 0x0F, 0x03, 0x00, 0x04, 0x06, 0x01, 0x0C, 0x07, 0x0B, 0x02, 0x05,
|
|
0x03, 0x0C, 0x04, 0x0A, 0x02, 0x0F, 0x0D, 0x0E, 0x07, 0x00, 0x05, 0x08, 0x01, 0x06, 0x0B, 0x09,
|
|
0x0A, 0x0C, 0x01, 0x00, 0x09, 0x0E, 0x0D, 0x0B, 0x03, 0x07, 0x0F, 0x08, 0x05, 0x02, 0x04, 0x06,
|
|
0x0E, 0x0A, 0x01, 0x08, 0x07, 0x06, 0x05, 0x0C, 0x02, 0x0F, 0x00, 0x0D, 0x03, 0x0B, 0x04, 0x09,
|
|
0x03, 0x08, 0x0E, 0x00, 0x07, 0x09, 0x0F, 0x0C, 0x01, 0x06, 0x0D, 0x02, 0x05, 0x0A, 0x0B, 0x04,
|
|
0x03, 0x0A, 0x0C, 0x04, 0x0D, 0x0B, 0x09, 0x0E, 0x0F, 0x06, 0x01, 0x07, 0x02, 0x00, 0x05, 0x08
|
|
]
|
|
|
|
static let W3_KEYLEN = 26
|
|
static let W3_BUFLEN = W3_KEYLEN * 2
|
|
|
|
var productValue: UInt32 = 0
|
|
var value1: UInt32 = 0
|
|
var value2: [UInt8] = []
|
|
|
|
public init(cdkey: String) throws {
|
|
precondition(cdkey.count == 26)
|
|
|
|
var table = [UInt8](repeating: 0, count: CdkeyDecodeAlpha26.W3_BUFLEN)
|
|
var values: [UInt32] = [0, 0, 0, 0]
|
|
|
|
tableLookup(key: cdkey.uppercased().utf8CString.map { Int($0) }, buf: &table)
|
|
|
|
// Multiplication rounds
|
|
for i in (0..<CdkeyDecodeAlpha26.W3_BUFLEN).reversed() {
|
|
var input = table[i]
|
|
|
|
for position in (0..<4).reversed() {
|
|
let x = Int64(values[position]) * 5
|
|
|
|
// Truncate to UInt32 and store
|
|
values[position] = UInt32(input) + UInt32(truncatingIfNeeded: x)
|
|
|
|
// Keep the carry bits only
|
|
input = UInt8(truncatingIfNeeded: x >> 32)
|
|
}
|
|
}
|
|
|
|
decodeKeyTablePass1(keyTable: &values)
|
|
decodeKeyTablePass2(keyTable: &values)
|
|
|
|
productValue = values[0] >> 0x0a
|
|
value1 = ((values[0] & 0x03FF) << 0x10) | (values[1] >> 0x10)
|
|
|
|
value2 = [UInt8]()
|
|
value2.append(UInt8(values[1] & 0xFF))
|
|
value2.append(UInt8((values[1] >> 8) & 0xFF))
|
|
value2.append(contentsOf: IntUtil.from32to8(values[2]))
|
|
value2.append(contentsOf: IntUtil.from32to8(values[3]))
|
|
|
|
}
|
|
|
|
func tableLookup(key: [Int], buf: inout [UInt8]) {
|
|
var a = 0
|
|
var b = 0x21
|
|
|
|
for i in 0..<CdkeyDecodeAlpha26.W3_KEYLEN {
|
|
a = (b + 0x07B5) % CdkeyDecodeAlpha26.W3_BUFLEN
|
|
b = (a + 0x07B5) % CdkeyDecodeAlpha26.W3_BUFLEN
|
|
|
|
let decode = CdkeyDecodeAlpha26.KeyTable[key[i]]
|
|
buf[a] = decode / 5
|
|
buf[b] = decode % 5
|
|
}
|
|
}
|
|
|
|
func decodeKeyTablePass1(keyTable: inout [UInt32]) {
|
|
|
|
for i: UInt32 in stride(from: 464, through: 0, by: -16) {
|
|
let var_8 = i / 16
|
|
let esi = (var_8 & 7) << 2
|
|
let outputIndex = 3 - Int(var_8) >> 3
|
|
var ebx = (keyTable[outputIndex] & (0x0F << esi)) >> esi
|
|
|
|
// Skip on first round
|
|
if (i < 464) {
|
|
for j in stride(from: 29, to: var_8, by: -1) {
|
|
let ecx = (j & 7) << 2
|
|
let ebp = (keyTable[0x03 - (Int(j) >> 3)] & (0x0F << ecx)) >> ecx
|
|
ebx = UInt32(CdkeyDecodeAlpha26.TranslateTable[Int(ebx + i)])
|
|
ebx = UInt32(CdkeyDecodeAlpha26.TranslateTable[Int(ebp ^ ebx + i)])
|
|
}
|
|
}
|
|
|
|
// Skip on last round
|
|
if (i > 0) {
|
|
for j: UInt32 in stride(from: var_8-1, through: 0, by: -1) {
|
|
let ecx = (j & 7) << 2;
|
|
var ebp = keyTable[Int(0x3 - (j >> 3))]
|
|
ebp &= (0xF << ecx)
|
|
ebp = ebp >> ecx
|
|
ebx = UInt32(CdkeyDecodeAlpha26.TranslateTable[Int(ebx + i)])
|
|
ebx = UInt32(CdkeyDecodeAlpha26.TranslateTable[Int(ebp ^ ebx + i)])
|
|
}
|
|
}
|
|
|
|
ebx = (UInt32(CdkeyDecodeAlpha26.TranslateTable[Int(ebx + i)]) & 0x0F) << esi;
|
|
|
|
keyTable[outputIndex] = ebx | ~(0x0F << esi) & keyTable[outputIndex]
|
|
}
|
|
}
|
|
|
|
func decodeKeyTablePass2(keyTable: inout [UInt32]) {
|
|
|
|
var valueMessageComposer = RawMessageComposer()
|
|
valueMessageComposer.write(keyTable[0])
|
|
valueMessageComposer.write(keyTable[1])
|
|
valueMessageComposer.write(keyTable[2])
|
|
valueMessageComposer.write(keyTable[3])
|
|
var valueMessageConsumer = RawMessageConsumer(message: valueMessageComposer.data)
|
|
|
|
for edi: UInt32 in 0..<120 {
|
|
|
|
let esi = (edi * 0x0B) % 120
|
|
let eax = edi & 0x1F
|
|
let ecx = esi & 0x1F
|
|
let edx = 3 - (edi >> 5)
|
|
|
|
let location = 12 - ((esi >> 5) << 2)
|
|
valueMessageConsumer.readIndex = Data.Index(location)
|
|
|
|
let ebp = (valueMessageConsumer.readUInt32() & (1 << ecx)) >> ecx
|
|
|
|
let lhs = ((ebp & 1) << eax)
|
|
let rhs = (~(1 << eax) & keyTable[Int(edx)])
|
|
keyTable[Int(edx)] = lhs | rhs
|
|
|
|
}
|
|
}
|
|
|
|
public func hashForAuthCheck(clientToken: UInt32, serverToken: UInt32) -> Data {
|
|
var hashComposer = RawMessageComposer()
|
|
hashComposer.write(clientToken)
|
|
hashComposer.write(serverToken)
|
|
hashComposer.write(productValue)
|
|
hashComposer.write(value1)
|
|
for x in value2 {
|
|
hashComposer.write(x)
|
|
}
|
|
let hash = Data(hashComposer.build()).sha1()
|
|
|
|
var dataComposer = RawMessageComposer()
|
|
dataComposer.write(26 as UInt32) // length
|
|
dataComposer.write(productValue)
|
|
dataComposer.write(value1)
|
|
dataComposer.write(0 as UInt32) // unknown
|
|
dataComposer.write(hash)
|
|
return dataComposer.build()
|
|
}
|
|
|
|
}
|