美文网首页加密和解密
RSA加密以及使用CocoaPods安装OpenSSL出现错误解

RSA加密以及使用CocoaPods安装OpenSSL出现错误解

作者: Andy_Livings | 来源:发表于2020-05-09 16:47 被阅读0次

项目中导入OpenSSL时的错误处理

[!] /bin/bash -c 
set -e
VERSION="1.0.2j"
SDKVERSION=`xcrun --sdk iphoneos --show-sdk-version 2> /dev/null`
MIN_SDK_VERSION_FLAG="-miphoneos-version-min=7.0"

BASEPATH="${PWD}"
CURRENTPATH="/tmp/openssl"
ARCHS="i386 x86_64 armv7 armv7s arm64"
DEVELOPER=`xcode-select -print-path`

mkdir -p "${CURRENTPATH}"
mkdir -p "${CURRENTPATH}/bin"

cp "file.tgz" "${CURRENTPATH}/file.tgz"
cd "${CURRENTPATH}"
tar -xzf file.tgz
cd "openssl-${VERSION}"

for ARCH in ${ARCHS}
do
  CONFIGURE_FOR="iphoneos-cross"

  if [ "${ARCH}" == "i386" ] || [ "${ARCH}" == "x86_64" ] ;
  then
    PLATFORM="iPhoneSimulator"
    if [ "${ARCH}" == "x86_64" ] ;
    then
      CONFIGURE_FOR="darwin64-x86_64-cc"
    fi
  else
    sed -ie "s!static volatile sig_atomic_t intr_signal;!static volatile intr_signal;!" "crypto/ui/ui_openssl.c"
    PLATFORM="iPhoneOS"
  fi

  export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer"
  export CROSS_SDK="${PLATFORM}${SDKVERSION}.sdk"

  echo "Building openssl-${VERSION} for ${PLATFORM} ${SDKVERSION} ${ARCH}"
  echo "Please stand by..."

  export CC="${DEVELOPER}/usr/bin/gcc -arch ${ARCH} ${MIN_SDK_VERSION_FLAG}"
  mkdir -p "${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk"
  LOG="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/build-openssl-${VERSION}.log"

  LIPO_LIBSSL="${LIPO_LIBSSL} ${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/lib/libssl.a"
  LIPO_LIBCRYPTO="${LIPO_LIBCRYPTO} ${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/lib/libcrypto.a"

  ./Configure ${CONFIGURE_FOR} --openssldir="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk" > "${LOG}" 2>&1
  sed -ie "s!^CFLAG=!CFLAG=-isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} !" "Makefile"

  make >> "${LOG}" 2>&1
  make all install_sw >> "${LOG}" 2>&1
  make clean >> "${LOG}" 2>&1
done


echo "Build library..."
rm -rf "${BASEPATH}/lib/"
mkdir -p "${BASEPATH}/lib/"
lipo -create ${LIPO_LIBSSL}    -output "${BASEPATH}/lib/libssl.a"
lipo -create ${LIPO_LIBCRYPTO} -output "${BASEPATH}/lib/libcrypto.a"

echo "Copying headers..."
rm -rf "${BASEPATH}/opensslIncludes/"
mkdir -p "${BASEPATH}/opensslIncludes/"
cp -RL "${CURRENTPATH}/openssl-${VERSION}/include/openssl" "${BASEPATH}/opensslIncludes/"

cd "${BASEPATH}"
echo "Building done."

echo "Cleaning up..."
rm -rf "${CURRENTPATH}"
echo "Done."

cp: file.tgz: No such file or directory

解决方法:

第一种解决方法:
使用pod 'OpenSSL-Universal'替换原来的pod 'OpenSSL' 
第二种方法:终端执行两面两个命令:
sudo gem uninstall cocoapods-downloader 
sudo gem install cocoapods-downloader -v 1.2.0
第三种方法:
rm -r ${TMPDIR}/openssl/ 
第四种方法:
 xcode -> preferences -> locations. 查看command line tools是否是空
然后执行pod install 

RSA加密和解密

相关知识

1、生成密文的长度等于密钥长度(密钥长度越大,生成密文的长度就越大,加密的速度就越慢,而密文也就越难被破解掉)。
2、不管明文长度是多少,RSA生成的密文长度总是固定的。
3、明文长度不能超过密钥长度,否则就会出问题(使用分段加密)。
4、RSA加密每次结果是不一样的(加密时对加密内容使用了长度为11位的随机填充)。
5、RSA本身不支持中文(一般使用URL编码来解决中文问题)。
6、公钥加密私钥解密,私钥加密公钥解密。

公钥/私钥(一般应该只会用到一个,另外一个是后台使用),一般是后台给的,自己生成也很简单,可以去网站上生成也可以使用终端生成。

RSA加密解密
#import "ASEncryptTool.h"
#import <openssl/pem.h>
#import <GTMBase64.h>
#import<CommonCrypto/CommonDigest.h>

typedef NS_ENUM(NSUInteger, RSAPaddingType)
{
    eRSAPaddingTypeNone      = RSA_NO_PADDING,
    eRSAPaddingTypePKCS1     = RSA_PKCS1_PADDING,
    eRSAPaddingTypeSSLV23    = RSA_SSLV23_PADDING
};

@implementation ASEncryptTool
{
    RSA *_publicRSA;//公钥的RAS
    RSA *_privateRSA;//私钥的RAS
}

+ (id)shareInstance
{
    static ASEncryptTool* encryptTool = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        encryptTool = [ASEncryptTool new];
    });
    return encryptTool;
}

/********************** key的格式化和处理(与加密无关,用来快速处理key)  START  **********************/

//0.1存放本地沙河路径
+(NSString*)RSAKeyFillePath:(KeyType)type
{
    NSString *keyFileName = @[
                              @"public_key.pem",
                              @"private_key.pem"
                              ][type];
    
    return [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:keyFileName];
}

//0.2格式化key
+ (NSString *)formattKey:(NSString *)key
{
    if (key == nil) return @"";
    
    NSInteger count = key.length / 64;
    NSMutableString *formattKey = key.mutableCopy;
    for (int i = 0; i < count; i ++)
    {
        [formattKey insertString:@"\n" atIndex:64 + (64 + 1) * i];
    }
    return formattKey == nil ? @"" : formattKey;
}

//0.3写入key文件
+ (BOOL)writeKey:(NSString *)key type:(KeyType)type;
{

    NSString*keyPath = [self RSAKeyFillePath:type];
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:keyPath])
    {
        return YES;
    }
    
    NSString *formattKey = [self formattKey:key];
    
    NSString *keyStr;
    switch (type)
    {
        case eKeyTypePublic:
        {
            keyStr = [NSString stringWithFormat:@"-----BEGIN PUBLIC KEY-----\n%@\n-----END PUBLIC KEY-----",formattKey];
            break;
        }
        case eKeyTypePrivate:
        {
            keyStr = [NSString stringWithFormat:@"-----BEGIN RSA PRIVATE KEY-----\n%@\n-----END RSA PRIVATE KEY-----",formattKey];
            break;
        }
        default:
        {
            return NO;
            
        }
    }
    NSLog(@"格式话处理过的key:\n%@\n",keyStr);
    NSError *error = nil;
    return [keyStr writeToFile:keyPath atomically:YES encoding:NSASCIIStringEncoding error:&error];
}

/********************** key的格式化和处理(与加密无关)  END  **********************/


//1.导入key为RSA结构体对象
- (BOOL)importRSAKey:(KeyType)type
{
    
//    这里是从项目中读取公钥和私钥,你也可以把公钥和私钥存入沙河中,从沙河中读取
    
    switch (type)
    {
        case eKeyTypePublic:
        {
            FILE *file = fopen([[[NSBundle mainBundle] pathForResource:@"public_key.pem" ofType:nil] UTF8String], "rb");
            if (file == NULL) return NO;
            _publicRSA = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL);
            assert(_publicRSA != nil);
            fclose(file);
            return (_publicRSA != NULL) ? YES : NO;
        }
        case eKeyTypePrivate:
        {
            FILE *file = fopen([[[NSBundle mainBundle] pathForResource:@"private_key.pem" ofType:nil] UTF8String], "rb");
            if (file == NULL) return NO;
            _privateRSA = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
            assert(_privateRSA != NULL);
            fclose(file);
            return (_privateRSA != NULL) ? YES : NO;
        }
        default:
        {
            return NO;
        }
    }
}

//2.1加密处理
- (NSData *)encryptToData:(NSString*)content type:(KeyType)type
{
    
    if([self RSAWithType:type] == NULL)
    {
        if (![self importRSAKey:type]) return nil;
    }
    
    RSA *rsa = [self RSAWithType:type];
    
    int status = 0;
    int length  = (int)content.length;
    unsigned char input[length + 1];
    bzero(input, length + 1);
    
    for (int i = 0; i < length; i++)
    {
        input[i] = [content characterAtIndex:i];
    }
    
    NSInteger  flen = [self getBlockSize:eRSAPaddingTypePKCS1 type:type];
    char *encryptData = (char*)malloc(flen);
    bzero(encryptData, flen);
    
    switch (type)
    {
        case eKeyTypePublic:
            status = RSA_public_encrypt(length, (unsigned char*)input, (unsigned char*)encryptData, rsa, eRSAPaddingTypePKCS1);
            break;
            
        default:
            status = RSA_private_encrypt(length, (unsigned char*)input, (unsigned char*)encryptData, rsa, eRSAPaddingTypePKCS1);
            break;
    }
    
    if (status)
    {
        NSData *returnData = [NSData dataWithBytes:encryptData length:status];
        free(encryptData);
        encryptData = NULL;
        return returnData;
    }
    
    free(encryptData);
    encryptData = NULL;
    
    return nil;
}

//2.2解密处理
- (NSString *)decryptToData:(NSString*)content type:(KeyType)type
{
    
    if([self RSAWithType:type] == NULL)
    {
        if (![self importRSAKey:type]) return nil;
    }
    
    RSA *rsa = [self RSAWithType:type];
    int status;
    NSData *data = [content base64Decode];
    int length = (int)data.length;
    
    NSInteger flen = [self getBlockSize:eRSAPaddingTypePKCS1 type:type];
    char *decryptData = (char*)malloc(flen);
    bzero(decryptData, flen);
    
    switch (type)
    {
        case eKeyTypePublic:
            status = RSA_public_decrypt(length, (unsigned char*)[data bytes], (unsigned char*)decryptData, rsa, eRSAPaddingTypePKCS1);
            break;
            
        default:
            status = RSA_private_decrypt(length, (unsigned char*)[data bytes], (unsigned char*)decryptData, rsa, eRSAPaddingTypePKCS1);
            break;
    }
    
    if (status)
    {
        NSMutableString *decryptString = [[NSMutableString alloc] initWithBytes:decryptData length:strlen(decryptData) encoding:NSASCIIStringEncoding];
        free(decryptData);
        decryptData = NULL;
        return decryptString;
    }
    
    free(decryptData);
    decryptData = NULL;
    
    return nil;
}

//3.1实现中文兼容和分段加密
- (NSString *)encrypt:(NSString *)content type:(KeyType)type
{
//    content = content.URLEncode;
    NSMutableString *encryptContent = @"".mutableCopy;
    for (NSInteger i = 0; i < ceilf(content.length / 117.0); i ++)
    {
        NSString *subStr = [content substringWithRange:NSMakeRange(i * 117, MIN(117, content.length - i * 117))];
        NSString *encryptSubStr = [[self encryptToData:subStr type:type] base64Encode];
        [encryptContent appendString:encryptSubStr];
    }
    return encryptContent;
}

//3.2实现中文兼容和分段解密
- (NSString *)decrypt:(NSString *)content type:(KeyType)type
{
    NSMutableString *decryptResult = @"".mutableCopy;
    for (NSInteger i = 0; i < ceilf(content.length / 117.0); i ++)
    {
        NSString *subStr = [content substringWithRange:NSMakeRange(i * 117, 117)];
        NSString *decryptSubStr = [self decryptToData:subStr type:type];
        NSString *decryptStr = decryptSubStr.length <= 117 ? decryptSubStr : [decryptSubStr substringToIndex:117];
        [decryptResult appendString:decryptStr];
    }
    return decryptResult;
//    return decryptResult.URLDecode;
}

//长度获取
- (int)getBlockSize:(RSAPaddingType)type type:(KeyType)keyType
{
    int len = RSA_size([self RSAWithType:keyType]);
    
    if (type != eRSAPaddingTypeNone)
    {
        len -= 11;
    }
    
    return len;
}

//根据类型获取对应的RSA
-(RSA*)RSAWithType:(KeyType)type
{
    switch (type)
    {
        case eKeyTypePublic:
        {
            return _publicRSA;
        }
        case eKeyTypePrivate:
        {
            return _privateRSA;
        }
        default:
        {
            return nil;
        }
    }
}

@end





@implementation NSString (Encode)

- (NSData*)base64Encode
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
    data = [GTMBase64 encodeData:data];
    return data;
}

- (NSData*)base64Decode
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
    data = [GTMBase64 decodeData:data];
    return data;
}

-(NSString*)URLDecode
{
    return self.stringByRemovingPercentEncoding;
}

-(NSString*)URLEncode
{
    return [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!*'\"();:@&=+$,/?%#[]% "].invertedSet];
}


@end


@implementation NSData (Encode)

- (NSString*)base64Encode
{
    return [[NSString alloc] initWithData:[GTMBase64 encodeData:self] encoding:NSUTF8StringEncoding];
}

- (NSString*)base64Decode
{
    return [[NSString alloc] initWithData:[GTMBase64 decodeData:self] encoding:NSUTF8StringEncoding];
}

@end

1、使用openSSL需要把公钥/私钥先转成RSA结构对象,然后进行加密解密。
2、解决中文的问题是使用url编码来解决的,这个要跟后台对接好就行,一般都会使用url编码,当然也可以使用其他的,只不过是做了个转换而已。
3、因为密文长度不能大于密钥长度,所以一般会进行分段加密,分段加密时密文控制是117,因为加密时对密文使用了长度为11的填充(随机的),加起来就是128(1024位对应的密钥/密文长度)。

demo下载地址

相关文章

网友评论

    本文标题:RSA加密以及使用CocoaPods安装OpenSSL出现错误解

    本文链接:https://www.haomeiwen.com/subject/dpofnhtx.html