0

我需要使用 PBEWithMD5AndDES JAVA 加密方法 PBEWithMD5AndDESJAVA PBEWithMD5AndDES来加密和解密我的密码 ,我需要像下面的代码一样快速进行加密和解密

@implementation CryptoHelper

#pragma mark -
#pragma mark Init Methods
- (id)init
{
    if(self = [super init])
    {

    }
    return self;
}

#pragma mark -
#pragma mark String Specific Methods

/** 
 *  Encrypts a string for social blast service. 
 *  
 *  @param  plainString The string to encrypt;
 *
 *  @return NSString    The encrypted string. 
 */
- (NSString *)encryptString: (NSString *) plainString{

    // Convert string to data and encrypt
    NSData *data = [self encryptPBEWithMD5AndDESData:[plainString dataUsingEncoding:NSUTF8StringEncoding] password:@"1111"];



    // Get encrypted string from data
    return [data base64EncodingWithLineLength:1024];

}


/** 
 *  Descrypts a string from social blast service. 
 *  
 *  @param  plainString The string to decrypt;
 *
 *  @return NSString    The decrypted string. 
 */
- (NSString *)decryptString: (NSString *) encryptedString{

    // decrypt the data
    NSData * data = [self decryptPBEWithMD5AndDESData:[NSData dataWithBase64EncodedString:encryptedString] password:@"1111"];

    // extract and return string
    return [NSString stringWithUTF8String:[data bytes]];

}


#pragma mark -
#pragma mark Crypto Methods

- (NSData *)encryptPBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password {
    return [self encodePBEWithMD5AndDESData:inData password:password direction:1];
}

- (NSData *)decryptPBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password {
    return [self encodePBEWithMD5AndDESData:inData password:password direction:0];
}

- (NSData *)encodePBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password direction:(int)direction
{
    NSLog(@"helper data = %@", inData);

    static const char gSalt[] =
    {
        (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA,
        (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA, (unsigned char)0xAA,
        (unsigned char)0x00
    };

    unsigned char *salt = (unsigned char *)gSalt;
    int saltLen = strlen(gSalt);
    int iterations = 15;

    EVP_CIPHER_CTX cipherCtx;


    unsigned char *mResults; // allocated storage of results
    int mResultsLen = 0;

    const char *cPassword = [password UTF8String];

    unsigned char *mData = (unsigned char *)[inData bytes];
    int mDataLen = [inData length];


    SSLeay_add_all_algorithms();
    X509_ALGOR *algorithm = PKCS5_pbe_set(NID_pbeWithMD5AndDES_CBC,
                                          iterations, salt, saltLen);



    memset(&cipherCtx, 0, sizeof(cipherCtx));

    if (algorithm != NULL)
    {
        EVP_CIPHER_CTX_init(&(cipherCtx));



        if (EVP_PBE_CipherInit(algorithm->algorithm, cPassword, strlen(cPassword),
                               algorithm->parameter, &(cipherCtx), direction))
        {

            EVP_CIPHER_CTX_set_padding(&cipherCtx, 1);

            int blockSize = EVP_CIPHER_CTX_block_size(&cipherCtx);
            int allocLen = mDataLen + blockSize + 1; // plus 1 for null terminator on decrypt
            mResults = (unsigned char *)OPENSSL_malloc(allocLen);


            unsigned char *in_bytes = mData;
            int inLen = mDataLen;
            unsigned char *out_bytes = mResults;
            int outLen = 0;



            int outLenPart1 = 0;
            if (EVP_CipherUpdate(&(cipherCtx), out_bytes, &outLenPart1, in_bytes, inLen))
            {
                out_bytes += outLenPart1;
                int outLenPart2 = 0;
                if (EVP_CipherFinal(&(cipherCtx), out_bytes, &outLenPart2))
                {
                    outLen += outLenPart1 + outLenPart2;
                    mResults[outLen] = 0;
                    mResultsLen = outLen;
                }
            } else {
                unsigned long err = ERR_get_error();

                ERR_load_crypto_strings();
                ERR_load_ERR_strings();
                char errbuff[256];
                errbuff[0] = 0;
                ERR_error_string_n(err, errbuff, sizeof(errbuff));
                NSLog(@"OpenSLL ERROR:\n\tlib:%s\n\tfunction:%s\n\treason:%s\n",
                      ERR_lib_error_string(err),
                      ERR_func_error_string(err),
                      ERR_reason_error_string(err));
                ERR_free_strings();
            }


            NSData *encryptedData = [NSData dataWithBytes:mResults length:mResultsLen]; //(NSData *)encr_buf;


            //NSLog(@"encryption result: %@\n", [encryptedData base64EncodingWithLineLength:1024]);

            EVP_cleanup();

            return encryptedData;
        }
    }
    EVP_cleanup();
    return nil;

}

@end
4

1 回答 1

3

PBEWithMD5AndDES 是指使用 MD5(消息摘要)散列函数和 DES(数据加密标准)的加密方法使用密钥导出函数(例如 PBKDF2(基于密码的密钥导出函数))对某些数据进行加密。

这可以在 iOS 中使用 Swift 使用 Common Crypto 轻松完成。

但这一切都是相当古老的,今天的最佳实践将使用 PBBKDF2 和 SHA 代替 MD5 和 AES 代替 DES。MD5 和 DES 非常周,不应该在新工作中使用。

如果您不需要与现有的加密文件进行互操作,您可以使用RNCryptor。另请参阅使用 RNCryptor Swift

如果您需要互操作,您可以使用 Common Crypto 拼凑一个匹配方案。如果您需要这样做,请为问题添加更多详细信息,包括示例现有代码和所有输入和输出的十六进制转储以及所有输入参数和您的 Swift 尝试代码。

已弃用文档部分的示例:

基于密码的密钥派生 2 (Swift 3+)

基于密码的密钥派生既可用于从密码文本派生加密密钥,也可用于保存密码以进行身份​​验证。

此示例代码提供了多种哈希算法,包括 SHA1、SHA256、SHA512。

rounds 参数用于使计算变慢,以便攻击者每次尝试都必须花费大量时间。典型的延迟值在 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>

CBC模式下的AES加密与随机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

于 2015-10-30T12:06:52.540 回答