Используя TripleDes и MD5 в быстром
У меня есть алгоритм в Java-код для использования tripleDes и MD5. Вот мой код Java:
private String _encrypt(String message, String secretKey) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 16);
SecretKey key = new SecretKeySpec(keyBytes, "DESede/ECB/PKCS7Padding");
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);
byte [] base64Bytes = Base64.encodeBase64(buf);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
я хочу использовать tripleDes и MD5 в swift, я конвертирую этот код Java в swift, но есть проблема в swift, потому что в java используется 16 байт, а swift использует 24 байт. Как можно решить эту разницу между кодированием в Java и Swift? Вот мой быстрый код:
func myEncrypt(encryptData:String) -> String?{
let myKeyData : NSData = ("Fanava@Wrapper!1395" as NSString).data(using: String.Encoding.utf8.rawValue)! as NSData
let myRawData : NSData = encryptData.data(using: String.Encoding.utf8)! as NSData
let mykeydatamd5 = Data(bytes: myKeyData.bytes, count: 24) // this key convert to 24 bytes but does not hash to md5
let mykeydatamd5 = Data(bytes: myKeyData.md5().bytes, count: 24) // this line converted key to md5(), 24byte, but it
let buffer_size : size_t = myRawData.length + kCCBlockSize3DES
let buffer = UnsafeMutablePointer<NSData>.allocate(capacity: buffer_size)
var num_bytes_encrypted : size_t = 0
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionECBMode | kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)
let Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm, options, mykeydatamd5.bytes , keyLength, nil, myRawData.bytes, myRawData.count, buffer, buffer_size, &num_bytes_encrypted)
if UInt32(Crypto_status) == UInt32(kCCSuccess){
let myResult: NSData = NSData(bytes: buffer, length: num_bytes_encrypted)
free(buffer)
return myResult.base64EncodedString(options: [])
}else{
free(buffer)
return nil
}
}
1 ответ
Вот пример кода, который можно легко изменить для TrippleDES:
Из раздела с заданной документацией SO
Для шифрования AES в режиме CBC со случайным IV (Swift 3+)
IV имеет префикс к зашифрованным данным
aesCBC128Encrypt
создаст случайный IV и префикс к зашифрованному коду.aesCBC128Decrypt
будет использовать префикс IV во время расшифровки.
Входные данные - это данные, а ключ - объекты данных. Если закодированная форма, такая как Base64, если требуется, преобразуйте в и / или из вызывающего метода.
Ключ должен иметь длину 128 бит (16 байтов), 192 бит (24 байта) или 256 бит (32 байта). Если используется другой размер ключа, будет выдано сообщение об ошибке.
PKCS # 7 заполнение установлено по умолчанию.
Этот пример требует Common Crypto
Необходимо иметь соединительный заголовок к проекту:#import <CommonCrypto/CommonCrypto.h>
Добавить Security.framework
к проекту.
Это пример, а не рабочий код.
enum AESError: Error {
case KeyError((String, Int))
case IVError((String, Int))
case CryptorError((String, Int))
}
// The iv is prefixed to the encrypted data
func aesCBCEncrypt(data:Data, keyData:Data) throws -> Data {
let keyLength = keyData.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if (validKeyLengths.contains(keyLength) == false) {
throw AESError.KeyError(("Invalid key length", keyLength))
}
let ivSize = kCCBlockSizeAES128;
let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
var cryptData = Data(count:cryptLength)
let status = cryptData.withUnsafeMutableBytes {ivBytes in
SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
}
if (status != 0) {
throw AESError.IVError(("IV generation failed", Int(status)))
}
var numBytesEncrypted :size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)
let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
options,
keyBytes, keyLength,
cryptBytes,
dataBytes, data.count,
cryptBytes+kCCBlockSizeAES128, cryptLength,
&numBytesEncrypted)
}
}
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.count = numBytesEncrypted + ivSize
}
else {
throw AESError.CryptorError(("Encryption failed", Int(cryptStatus)))
}
return cryptData;
}
// The iv is prefixed to the encrypted data
func aesCBCDecrypt(data:Data, keyData:Data) throws -> Data? {
let keyLength = keyData.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if (validKeyLengths.contains(keyLength) == false) {
throw AESError.KeyError(("Invalid key length", keyLength))
}
let ivSize = kCCBlockSizeAES128;
let clearLength = size_t(data.count - ivSize)
var clearData = Data(count:clearLength)
var numBytesDecrypted :size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)
let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCDecrypt),
CCAlgorithm(kCCAlgorithmAES128),
options,
keyBytes, keyLength,
dataBytes,
dataBytes+kCCBlockSizeAES128, clearLength,
cryptBytes, clearLength,
&numBytesDecrypted)
}
}
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
clearData.count = numBytesDecrypted
}
else {
throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
}
return clearData;
}
Пример использования:
let clearData = "clearData0123456".data(using:String.Encoding.utf8)!
let keyData = "keyData890123456".data(using:String.Encoding.utf8)!
print("clearData: \(clearData as NSData)")
print("keyData: \(keyData as NSData)")
var cryptData :Data?
do {
cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
print("cryptData: \(cryptData! as NSData)")
}
catch (let status) {
print("Error aesCBCEncrypt: \(status)")
}
let decryptData :Data?
do {
let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
print("decryptData: \(decryptData! as NSData)")
}
catch (let status) {
print("Error aesCBCDecrypt: \(status)")
}
Пример вывода:
clearData: <636c6561 72446174 61303132 33343536>
keyData: <6b657944 61746138 39303132 33343536>
cryptData: <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>
Заметки:
Типичная проблема с примером кода в режиме CBC состоит в том, что он оставляет создание и передачу случайного IV пользователю. Этот пример включает генерацию IV, с префиксом зашифрованных данных и использует префикс IV во время дешифрования. Это освобождает случайного пользователя от деталей, которые необходимы для режима CBC.
В целях безопасности зашифрованные данные также должны иметь аутентификацию, этот пример кода не обеспечивает ее для того, чтобы быть маленькой и обеспечивать лучшую совместимость для других платформ.
Также отсутствует вывод ключа из пароля, предлагается использовать PBKDF2, если в качестве ключевого материала используются текстовые пароли.
Для надежного готового к использованию многоплатформенного кода шифрования см. RNCryptor.
При необходимости эта функция может быть изменена для 3DES.
Для шифрования PBKDF2 ** Получение ключа на основе пароля 2 (Swift 3+)
Получение ключа на основе пароля может использоваться как для получения ключа шифрования из текста пароля, так и для сохранения пароля в целях аутентификации.
Существует несколько алгоритмов хеширования, включая SHA1, SHA256, SHA512, которые предоставлены в этом примере кода.
Параметр раундов используется для замедления вычислений, поэтому злоумышленнику приходится тратить значительное время на каждую попытку. Типичные значения задержки находятся в диапазоне от 100 мс до 500 мс, более короткие значения могут использоваться, если есть недопустимая производительность.
Этот пример требует Common Crypto
Необходимо иметь соединительный заголовок к проекту:#import <CommonCrypto/CommonCrypto.h>
Добавить Security.framework
к проекту.
Параметры:
password password String
salt salt Data
keyByteCount number of key bytes to generate
rounds Iteration rounds
returns Derived key
func pbkdf2SHA1(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA1), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}
func pbkdf2SHA256(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}
func pbkdf2SHA512(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
return pbkdf2(hash:CCPBKDFAlgorithm(kCCPRFHmacAlgSHA512), password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
}
func pbkdf2(hash :CCPBKDFAlgorithm, password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data? {
let passwordData = password.data(using:String.Encoding.utf8)!
var derivedKeyData = Data(repeating:0, count:keyByteCount)
let derivationStatus = derivedKeyData.withUnsafeMutableBytes {derivedKeyBytes in
salt.withUnsafeBytes { saltBytes in
CCKeyDerivationPBKDF(
CCPBKDFAlgorithm(kCCPBKDF2),
password, passwordData.count,
saltBytes, salt.count,
hash,
UInt32(rounds),
derivedKeyBytes, derivedKeyData.count)
}
}
if (derivationStatus != 0) {
print("Error: \(derivationStatus)")
return nil;
}
return derivedKeyData
}
Пример использования:
let password = "password"
//let salt = "saltData".data(using: String.Encoding.utf8)!
let salt = Data(bytes: [0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61])
let keyByteCount = 16
let rounds = 100000
let derivedKey = pbkdf2SHA1(password:password, salt:salt, keyByteCount:keyByteCount, rounds:rounds)
print("derivedKey (SHA1): \(derivedKey! as NSData)")
Пример вывода:
derivedKey (SHA1): <6b9d4fa3 0385d128 f6d196ee 3f1d6dbf>