Files
Leeksov 4647310322 GLEGram 12.5 — Initial public release
Based on Swiftgram 12.5 (Telegram iOS 12.5).
All GLEGram features ported and organized in GLEGram/ folder.

Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass,
Font Replacement, Fake Profile, Chat Export, Plugin System, and more.

See CHANGELOG_12.5.md for full details.
2026-04-06 09:48:12 +03:00

98 lines
3.8 KiB
Swift

import Foundation
import Security
import CryptoKit
/// Key derivation for local encryption (key not stored derived from app identity).
private func deriveLocalKey() -> SymmetricKey {
let salt = "sg_local_v1_7f3a9e"
let seed = (Bundle.main.bundleIdentifier ?? "sg") + salt
let hash = SHA256.hash(data: Data(Array(seed.utf8)))
return SymmetricKey(data: hash)
}
/// AES-256-GCM encrypt before Keychain write. Protects against Keychain-substitution tweaks.
private func encryptForStorage(_ plaintext: Data) -> Data? {
let key = deriveLocalKey()
let nonce = AES.GCM.Nonce()
guard let sealed = try? AES.GCM.seal(plaintext, using: key, nonce: nonce),
let combined = sealed.combined else { return nil }
return combined
}
/// AES-256-GCM decrypt after Keychain read.
private func decryptFromStorage(_ ciphertext: Data) -> Data? {
let key = deriveLocalKey()
guard let sealed = try? AES.GCM.SealedBox(combined: ciphertext),
let decrypted = try? AES.GCM.open(sealed, using: key) else { return nil }
return decrypted
}
/// Keychain + AES-256-GCM. Data is encrypted before Keychain; substitution tweaks get ciphertext only.
private enum SupportersSecureStorage {
private static let service = "sg_glegram_secure"
private static let accessibility = kSecAttrAccessibleWhenUnlockedThisDeviceOnly
static func getData(account: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
guard status == errSecSuccess, let ciphertext = result as? Data else {
return nil
}
return decryptFromStorage(ciphertext)
}
static func setData(_ plaintext: Data, account: String) -> Bool {
guard let ciphertext = encryptForStorage(plaintext) else { return false }
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecAttrAccessible as String: accessibility
]
var status = SecItemCopyMatching(query as CFDictionary, nil)
if status == errSecSuccess {
let updateQuery: [String: Any] = [kSecValueData as String: ciphertext]
status = SecItemUpdate(query as CFDictionary, updateQuery as CFDictionary)
return status == errSecSuccess
} else if status == errSecItemNotFound {
var addQuery = query
addQuery[kSecValueData as String] = ciphertext
status = SecItemAdd(addQuery as CFDictionary, nil)
return status == errSecSuccess
}
return false
}
static func delete(account: String) -> Bool {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account
]
let status = SecItemDelete(query as CFDictionary)
return status == errSecSuccess || status == errSecItemNotFound
}
}
func supportersSecureLoadJSON(account: String) -> [String: Any]? {
guard let data = SupportersSecureStorage.getData(account: account),
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
return nil
}
return json
}
func supportersSecureSaveJSON(_ dict: [String: Any], account: String) -> Bool {
guard let data = try? JSONSerialization.data(withJSONObject: dict) else {
return false
}
return SupportersSecureStorage.setData(data, account: account)
}