Last active
March 8, 2025 13:06
-
-
Save felipebweber/fe0d7dff40f65655e8302de2eed705bc to your computer and use it in GitHub Desktop.
Crypt-ptbr
This file contains hidden or 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
import CryptoKit | |
import Foundation | |
import CommonCrypto | |
struct Crypt { | |
private static let secretKey = "s3cr3tKeY!" | |
static func deriveKey(timestamp: Int) throws -> SymmetricKey { | |
let salt = "\(timestamp)".data(using: .utf8)! | |
let password = secretKey.data(using: .utf8)! | |
var derivedKey = [UInt8](repeating: 0, count: 32) | |
CCKeyDerivationPBKDF( | |
CCPBKDFAlgorithm(kCCPBKDF2), | |
password.withUnsafeBytes { $0.baseAddress?.assumingMemoryBound(to: Int8.self) }, | |
password.count, | |
salt.withUnsafeBytes { $0.baseAddress?.assumingMemoryBound(to: UInt8.self) }, | |
salt.count, | |
CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256), | |
UInt32(100000), | |
&derivedKey, | |
derivedKey.count | |
) | |
return SymmetricKey(data: Data(derivedKey)) | |
} | |
static func encrypt(data: String) throws -> String { | |
let timestamp = Int(Date().timeIntervalSince1970) | |
let key = try deriveKey(timestamp: timestamp) | |
let iv = AES.GCM.Nonce() | |
let sealedBox = try AES.GCM.seal(data.data(using: .utf8)!, using: key, nonce: iv) | |
let encryptedData = sealedBox.ciphertext | |
let tag = sealedBox.tag | |
// Calcular HMAC (encryptedData + iv + timestamp) | |
let hmacKey = SymmetricKey(data: key.withUnsafeBytes { Data($0) }) | |
let hmac = HMAC<SHA256>.authenticationCode( | |
for: encryptedData + iv.withUnsafeBytes { Data($0) } + Data("\(timestamp)".utf8), | |
using: hmacKey | |
) | |
// Formatar payload: encryptedData|iv|tag|hmac | |
let payload = [ | |
encryptedData.base64EncodedString(), | |
iv.withUnsafeBytes { Data($0) }.base64EncodedString(), | |
tag.base64EncodedString(), | |
Data(hmac).base64EncodedString() | |
].joined(separator: "|") | |
return payload | |
} | |
static func decrypt(payload: String) throws -> String { | |
let parts = payload.components(separatedBy: "|") | |
guard parts.count == 4 else { throw NSError(domain: "Invalid payload", code: 1) } | |
let encryptedData = Data(base64Encoded: parts[0])! | |
let ivData = Data(base64Encoded: parts[1])! | |
let tag = Data(base64Encoded: parts[2])! | |
let hmac = Data(base64Encoded: parts[3])! | |
let timestamp = Int(Date().timeIntervalSince1970) | |
// Verificar timestamp | |
if abs(Int(Date().timeIntervalSince1970) - timestamp) > 300 { | |
throw NSError(domain: "Timestamp expirado", code: 2) | |
} | |
let key = try deriveKey(timestamp: timestamp) | |
// Verificar HMAC | |
let hmacKey = SymmetricKey(data: key.withUnsafeBytes { Data($0) }) | |
let calculatedHmac = HMAC<SHA256>.authenticationCode( | |
for: encryptedData + ivData + Data("\(timestamp)".utf8), | |
using: hmacKey | |
) | |
guard hmac == Data(calculatedHmac) else { | |
throw NSError(domain: "HMAC inválido", code: 3) | |
} | |
// Descriptografar | |
let sealedBox = try AES.GCM.SealedBox( | |
nonce: AES.GCM.Nonce(data: ivData), | |
ciphertext: encryptedData, | |
tag: tag | |
) | |
let decryptedData = try AES.GCM.open(sealedBox, using: key) | |
return String(data: decryptedData, encoding: .utf8)! | |
} | |
} | |
// Como usar | |
let encrypted = try! Crypt.encrypt(data: "Dados secretos") | |
print("Encrypted data: \(encrypted)") | |
let decrypted = try! Crypt.decrypt(payload: encrypted) | |
print("Decrypted data: \(decrypted)") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment