mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Refactoring
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import MtProtoKit
|
||||
|
||||
import SyncCore
|
||||
|
||||
private func messageKey(key: SecretChatKey, msgKey: UnsafeRawPointer, mode: SecretChatEncryptionMode) -> (aesKey: Data, aesIv: Data) {
|
||||
switch mode {
|
||||
case .v1:
|
||||
let x: Int = 0
|
||||
|
||||
var sha1AData = Data()
|
||||
sha1AData.count = 16 + 32
|
||||
sha1AData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
memcpy(bytes, msgKey, 16)
|
||||
memcpy(bytes.advanced(by: 16), key.key.memory.advanced(by: x), 32)
|
||||
}
|
||||
let sha1A = MTSha1(sha1AData)!
|
||||
|
||||
var sha1BData = Data()
|
||||
sha1BData.count = 16 + 16 + 16
|
||||
sha1BData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
memcpy(bytes, key.key.memory.advanced(by: 32 + x), 16)
|
||||
memcpy(bytes.advanced(by: 16), msgKey, 16)
|
||||
memcpy(bytes.advanced(by: 16 + 16), key.key.memory.advanced(by: 48 + x), 16)
|
||||
}
|
||||
let sha1B = MTSha1(sha1BData)!
|
||||
|
||||
var sha1CData = Data()
|
||||
sha1CData.count = 32 + 16
|
||||
sha1CData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
memcpy(bytes, key.key.memory.advanced(by: 64 + x), 32)
|
||||
memcpy(bytes.advanced(by: 32), msgKey, 16)
|
||||
}
|
||||
let sha1C = MTSha1(sha1CData)!
|
||||
|
||||
var sha1DData = Data()
|
||||
sha1DData.count = 16 + 32
|
||||
sha1DData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
memcpy(bytes, msgKey, 16)
|
||||
memcpy(bytes.advanced(by: 16), key.key.memory.advanced(by: 96 + x), 32)
|
||||
}
|
||||
let sha1D = MTSha1(sha1DData)!
|
||||
|
||||
var aesKey = Data()
|
||||
aesKey.count = 8 + 12 + 12
|
||||
aesKey.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
sha1A.withUnsafeBytes { (sha1A: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(bytes, sha1A, 8)
|
||||
}
|
||||
sha1B.withUnsafeBytes { (sha1B: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(bytes.advanced(by: 8), sha1B.advanced(by: 8), 12)
|
||||
}
|
||||
sha1C.withUnsafeBytes { (sha1C: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(bytes.advanced(by: 8 + 12), sha1C.advanced(by: 4), 12)
|
||||
}
|
||||
}
|
||||
|
||||
var aesIv = Data()
|
||||
aesIv.count = 12 + 8 + 4 + 8
|
||||
aesIv.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
sha1A.withUnsafeBytes { (sha1A: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(bytes, sha1A.advanced(by: 8), 12)
|
||||
}
|
||||
sha1B.withUnsafeBytes { (sha1B: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(bytes.advanced(by: 12), sha1B, 8)
|
||||
}
|
||||
sha1C.withUnsafeBytes { (sha1C: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(bytes.advanced(by: 12 + 8), sha1C.advanced(by: 16), 4)
|
||||
}
|
||||
sha1D.withUnsafeBytes { (sha1D: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(bytes.advanced(by: 12 + 8 + 4), sha1D, 8)
|
||||
}
|
||||
}
|
||||
return (aesKey, aesIv)
|
||||
case let .v2(role):
|
||||
var xValue: Int
|
||||
switch role {
|
||||
case .creator:
|
||||
xValue = 0
|
||||
case .participant:
|
||||
xValue = 8
|
||||
}
|
||||
|
||||
var sha256_a_data = Data()
|
||||
sha256_a_data.append(msgKey.assumingMemoryBound(to: UInt8.self), count: 16)
|
||||
sha256_a_data.append(key.key.memory.assumingMemoryBound(to: UInt8.self).advanced(by: xValue), count: 36)
|
||||
|
||||
let sha256_a = MTSha256(sha256_a_data)!
|
||||
|
||||
var sha256_b_data = Data()
|
||||
sha256_b_data.append(key.key.memory.assumingMemoryBound(to: UInt8.self).advanced(by: 40 + xValue), count: 36)
|
||||
sha256_b_data.append(msgKey.assumingMemoryBound(to: UInt8.self), count: 16)
|
||||
|
||||
let sha256_b = MTSha256(sha256_b_data)!
|
||||
|
||||
var aesKey = Data()
|
||||
aesKey.append(sha256_a.subdata(in: 0 ..< (0 + 8)))
|
||||
aesKey.append(sha256_b.subdata(in: 8 ..< (8 + 16)))
|
||||
aesKey.append(sha256_a.subdata(in: 24 ..< (24 + 8)))
|
||||
|
||||
var aesIv = Data()
|
||||
aesIv.append(sha256_b.subdata(in: 0 ..< (0 + 8)))
|
||||
aesIv.append(sha256_a.subdata(in: 8 ..< (8 + 16)))
|
||||
aesIv.append(sha256_b.subdata(in: 24 ..< (24 + 8)))
|
||||
|
||||
return (aesKey, aesIv)
|
||||
}
|
||||
}
|
||||
|
||||
func withDecryptedMessageContents(parameters: SecretChatEncryptionParameters, data: MemoryBuffer) -> MemoryBuffer? {
|
||||
assert(parameters.key.key.length == 256)
|
||||
|
||||
if data.length < 4 + 16 + 16 {
|
||||
return nil
|
||||
}
|
||||
|
||||
let msgKey = data.memory.advanced(by: 8)
|
||||
|
||||
switch parameters.mode {
|
||||
case .v1:
|
||||
let (aesKey, aesIv) = messageKey(key: parameters.key, msgKey: msgKey, mode: parameters.mode)
|
||||
|
||||
let decryptedData = MTAesDecrypt(Data(bytes: data.memory.advanced(by: 8 + 16), count: data.length - (8 + 16)), aesKey, aesIv)!
|
||||
|
||||
if decryptedData.count < 4 * 3 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var payloadLength: Int32 = 0
|
||||
decryptedData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(&payloadLength, bytes, 4)
|
||||
}
|
||||
|
||||
let paddingLength = decryptedData.count - (Int(payloadLength) + 4)
|
||||
if Int(payloadLength) > decryptedData.count - 4 || paddingLength > 16 {
|
||||
return nil
|
||||
}
|
||||
|
||||
let calculatedMsgKeyData = MTSubdataSha1(decryptedData, 0, UInt(payloadLength) + 4)!
|
||||
let msgKeyMatches = calculatedMsgKeyData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Bool in
|
||||
return memcmp(bytes.advanced(by: calculatedMsgKeyData.count - 16), msgKey, 16) == 0
|
||||
}
|
||||
|
||||
if !msgKeyMatches {
|
||||
return nil
|
||||
}
|
||||
|
||||
let result = decryptedData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Data in
|
||||
return Data(bytes: bytes.advanced(by: 4), count: Int(payloadLength))
|
||||
}
|
||||
return MemoryBuffer(data: result)
|
||||
case let .v2(role):
|
||||
let senderRole: SecretChatRole
|
||||
switch role {
|
||||
case .creator:
|
||||
senderRole = .participant
|
||||
case .participant:
|
||||
senderRole = .creator
|
||||
}
|
||||
let (aesKey, aesIv) = messageKey(key: parameters.key, msgKey: msgKey, mode: .v2(role: senderRole))
|
||||
|
||||
let decryptedData = MTAesDecrypt(Data(bytes: data.memory.advanced(by: 8 + 16), count: data.length - (8 + 16)), aesKey, aesIv)!
|
||||
|
||||
if decryptedData.count < 4 * 3 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var payloadLength: Int32 = 0
|
||||
decryptedData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(&payloadLength, bytes, 4)
|
||||
}
|
||||
|
||||
let paddingLength = decryptedData.count - (Int(payloadLength) + 4)
|
||||
|
||||
let xValue: Int
|
||||
switch role {
|
||||
case .creator:
|
||||
xValue = 8
|
||||
case .participant:
|
||||
xValue = 0
|
||||
}
|
||||
|
||||
var keyLargeData = Data()
|
||||
keyLargeData.append(parameters.key.key.memory.assumingMemoryBound(to: UInt8.self).advanced(by: 88 + xValue), count: 32)
|
||||
keyLargeData.append(decryptedData)
|
||||
|
||||
let keyLarge = MTSha256(keyLargeData)!
|
||||
let localMessageKey = keyLarge.subdata(in: 8 ..< (8 + 16))
|
||||
|
||||
let msgKeyData = Data(bytes: msgKey.assumingMemoryBound(to: UInt8.self), count: 16)
|
||||
|
||||
if Int(payloadLength) <= 0 || Int(payloadLength) > decryptedData.count - 4 || paddingLength < 12 || paddingLength > 1024 {
|
||||
|
||||
if localMessageKey != msgKeyData {
|
||||
Logger.shared.log("SecretChatEncryption", "message key doesn't match (length check)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if localMessageKey != msgKeyData {
|
||||
Logger.shared.log("SecretChatEncryption", "message key doesn't match")
|
||||
return nil
|
||||
}
|
||||
|
||||
let result = decryptedData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Data in
|
||||
return Data(bytes: bytes.advanced(by: 4), count: Int(payloadLength))
|
||||
}
|
||||
return MemoryBuffer(data: result)
|
||||
}
|
||||
}
|
||||
|
||||
enum SecretChatEncryptionMode {
|
||||
case v1
|
||||
case v2(role: SecretChatRole)
|
||||
}
|
||||
|
||||
struct SecretChatEncryptionParameters {
|
||||
let key: SecretChatKey
|
||||
let mode: SecretChatEncryptionMode
|
||||
}
|
||||
|
||||
func encryptedMessageContents(parameters: SecretChatEncryptionParameters, data: MemoryBuffer) -> Data {
|
||||
var payloadLength: Int32 = Int32(data.length)
|
||||
var payloadData = Data()
|
||||
withUnsafeBytes(of: &payloadLength, { bytes -> Void in
|
||||
payloadData.append(bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), count: 4)
|
||||
})
|
||||
payloadData.append(data.memory.assumingMemoryBound(to: UInt8.self), count: data.length)
|
||||
|
||||
switch parameters.mode {
|
||||
case .v1:
|
||||
var msgKey = MTSha1(payloadData)!
|
||||
msgKey.replaceSubrange(0 ..< (msgKey.count - 16), with: Data())
|
||||
|
||||
var randomBuf = malloc(16)!
|
||||
defer {
|
||||
free(randomBuf)
|
||||
}
|
||||
let randomBytes = randomBuf.assumingMemoryBound(to: UInt8.self)
|
||||
arc4random_buf(randomBuf, 16)
|
||||
|
||||
var randomIndex = 0
|
||||
while payloadData.count % 16 != 0 {
|
||||
payloadData.append(randomBytes.advanced(by: randomIndex), count: 1)
|
||||
randomIndex += 1
|
||||
}
|
||||
|
||||
let (aesKey, aesIv) = msgKey.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> (Data, Data) in
|
||||
return messageKey(key: parameters.key, msgKey: bytes, mode: parameters.mode)
|
||||
}
|
||||
|
||||
let encryptedData = MTAesEncrypt(payloadData, aesKey, aesIv)!
|
||||
var encryptedPayload = Data()
|
||||
var keyFingerprint: Int64 = parameters.key.fingerprint
|
||||
withUnsafeBytes(of: &keyFingerprint, { bytes -> Void in
|
||||
encryptedPayload.append(bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), count: 8)
|
||||
})
|
||||
encryptedPayload.append(msgKey)
|
||||
encryptedPayload.append(encryptedData)
|
||||
return encryptedPayload
|
||||
case let .v2(role):
|
||||
var randomBytes = Data(count: 128)
|
||||
let randomBytesCount = randomBytes.count
|
||||
randomBytes.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<Int8>) -> Void in
|
||||
arc4random_buf(bytes, randomBytesCount)
|
||||
}
|
||||
|
||||
var decryptedData = payloadData
|
||||
var take = 0
|
||||
while take < 12 {
|
||||
decryptedData.append(randomBytes.subdata(in: take ..< (take + 1)))
|
||||
take += 1
|
||||
}
|
||||
|
||||
while decryptedData.count % 16 != 0 {
|
||||
decryptedData.append(randomBytes.subdata(in: take ..< (take + 1)))
|
||||
take += 1
|
||||
}
|
||||
|
||||
var remainingCount = Int(arc4random_uniform(UInt32(72 + 1 - take)))
|
||||
while remainingCount % 16 != 0 {
|
||||
remainingCount -= 1
|
||||
}
|
||||
|
||||
for _ in 0 ..< remainingCount {
|
||||
decryptedData.append(randomBytes.subdata(in: take ..< (take + 1)))
|
||||
take += 1
|
||||
}
|
||||
|
||||
var xValue: Int
|
||||
switch role {
|
||||
case .creator:
|
||||
xValue = 0
|
||||
case .participant:
|
||||
xValue = 8
|
||||
}
|
||||
|
||||
var keyData = Data()
|
||||
keyData.append(parameters.key.key.memory.assumingMemoryBound(to: UInt8.self).advanced(by: 88 + xValue), count: 32)
|
||||
|
||||
keyData.append(decryptedData)
|
||||
|
||||
let keyLarge = MTSha256(keyData)!
|
||||
|
||||
let msgKey = keyLarge.subdata(in: 8 ..< (8 + 16))
|
||||
|
||||
let (aesKey, aesIv) = msgKey.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> (Data, Data) in
|
||||
return messageKey(key: parameters.key, msgKey: bytes, mode: parameters.mode)
|
||||
}
|
||||
|
||||
let encryptedData = MTAesEncrypt(decryptedData, aesKey, aesIv)!
|
||||
var encryptedPayload = Data()
|
||||
var keyFingerprint: Int64 = parameters.key.fingerprint
|
||||
withUnsafeBytes(of: &keyFingerprint, { bytes -> Void in
|
||||
encryptedPayload.append(bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), count: 8)
|
||||
})
|
||||
encryptedPayload.append(msgKey)
|
||||
encryptedPayload.append(encryptedData)
|
||||
return encryptedPayload
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user