기본 콘텐츠로 건너뛰기

IOS - RSA 공개키 암호화 (Modulus, Exponent 사용) - 64bit 정책 대응방법 포함

====================================================================
64bit 대응 완료
2014. 12. 22 (월) 
애플 앱스토어에는 2015년 2월 1일부터 64bit 어플리케이션만 배포 가능하므로 이에 대응한 
RSA 암호화 로직 적용방안을 추가로 작성했습니다. 

1. 주제 : IOS ( Objective-C) RSA 암호화  (RSA Encryption) 
2. 적용방법 요약
  1) 키 생성  ( 웹서버 - Java) 
 - 로그인 암호화를 위해 웹서버에서 (java) RSA 공개키와 개인키를 만든다. 
 - 만들어진 공개키에서 Modulus 와 Exponent 를 뽑아낸다. 
   (이때 만들어진 modulus와 exponent 값은 16진수이다.  /  base64인코딩은 하지 않음)

  2) 키 수신 
  - 아이폰에서 암호화에 사용할 공개키 정보를 웹서버에 요청한다음 modulus와 exponent 값을 수신받는다. 
  
  3) 암호화
  - 수신받은 modulus와 exponent를 사용해서 암호화를 진행! 

------------------------------------

1. openssl 정적 라이브러리 획득 
소스 다운로드부터 64bit 컴파일이 가능한 정적라이브러리 형태로 완성시켜주는 스크립트가 있으므로 
맥에서 터미널을 실행한뒤 아무장소에서나 아래 스크립트를 vi 에디터로 만든다음 실행하시면
실행한 위치에 include 와 lib 디렉토리가 생깁니다. 



oepnssl-build.sh


#!/bin/sh
# Automatic build script for libssl and libcrypto
# for iPhoneOS and iPhoneSimulator
#
# Created by Felix Schulze on 16.12.10.
# Copyright 2010 Felix Schulze. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
###########################################################################
# Change values here #
#
VERSION="1.0.1j" #
SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version` #
# #
###########################################################################
# #
# Don't change anything under this line! #
# #
###########################################################################
CURRENTPATH=`pwd`
ARCHS="i386 x86_64 armv7 armv7s arm64"
DEVELOPER=`xcode-select -print-path`
if [ ! -d "$DEVELOPER" ]; then
echo "xcode path is not set correctly $DEVELOPER does not exist (most likely because of xcode > 4.3)"
echo "run"
echo "sudo xcode-select -switch <xcode path>"
echo "for default installation:"
echo "sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer"
exit 1
fi
case $DEVELOPER in
*\ * )
echo "Your Xcode path contains whitespaces, which is not supported."
exit 1
;;
esac
case $CURRENTPATH in
*\ * )
echo "Your path contains whitespaces, which is not supported by 'make install'."
exit 1
;;
esac
set -e
if [ ! -e openssl-${VERSION}.tar.gz ]; then
echo "Downloading openssl-${VERSION}.tar.gz"
curl -O https://www.openssl.org/source/openssl-${VERSION}.tar.gz
else
echo "Using openssl-${VERSION}.tar.gz"
fi
mkdir -p "${CURRENTPATH}/src"
mkdir -p "${CURRENTPATH}/bin"
mkdir -p "${CURRENTPATH}/lib"
tar zxf openssl-${VERSION}.tar.gz -C "${CURRENTPATH}/src"
cd "${CURRENTPATH}/src/openssl-${VERSION}"
for ARCH in ${ARCHS}
do
if [[ "${ARCH}" == "i386" || "${ARCH}" == "x86_64" ]];
then
PLATFORM="iPhoneSimulator"
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"
export BUILD_TOOLS="${DEVELOPER}"
echo "Building openssl-${VERSION} for ${PLATFORM} ${SDKVERSION} ${ARCH}"
echo "Please stand by..."
export CC="${BUILD_TOOLS}/usr/bin/gcc -arch ${ARCH}"
mkdir -p "${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk"
LOG="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/build-openssl-${VERSION}.log"
set +e
if [[ "$VERSION" =~ 1.0.0. ]]; then
./Configure BSD-generic32 --openssldir="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk" > "${LOG}" 2>&1
elif [ "${ARCH}" == "x86_64" ]; then
./Configure darwin64-x86_64-cc --openssldir="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk" > "${LOG}" 2>&1
else
./Configure iphoneos-cross --openssldir="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk" > "${LOG}" 2>&1
fi
if [ $? != 0 ];
then
echo "Problem while configure - Please check ${LOG}"
exit 1
fi
# add -isysroot to CC=
sed -ie "s!^CFLAG=!CFLAG=-isysroot ${CROSS_TOP}/SDKs/${CROSS_SDK} -miphoneos-version-min=7.0 !" "Makefile"
if [ "$1" == "verbose" ];
then
make
else
make >> "${LOG}" 2>&1
fi
if [ $? != 0 ];
then
echo "Problem while make - Please check ${LOG}"
exit 1
fi
set -e
make install >> "${LOG}" 2>&1
make clean >> "${LOG}" 2>&1
done
echo "Build library..."
lipo -create ${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}-i386.sdk/lib/libssl.a ${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}-x86_64.sdk/lib/libssl.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7.sdk/lib/libssl.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7s.sdk/lib/libssl.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-arm64.sdk/lib/libssl.a -output ${CURRENTPATH}/lib/libssl.a
lipo -create ${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}-i386.sdk/lib/libcrypto.a ${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}-x86_64.sdk/lib/libcrypto.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7.sdk/lib/libcrypto.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7s.sdk/lib/libcrypto.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-arm64.sdk/lib/libcrypto.a -output ${CURRENTPATH}/lib/libcrypto.a
mkdir -p ${CURRENTPATH}/include
cp -R ${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}-i386.sdk/include/openssl ${CURRENTPATH}/include/
echo "Building done."
echo "Cleaning up..."
rm -rf ${CURRENTPATH}/src/openssl-${VERSION}
echo "Done."

2. 현재 위치에 생성된 lib 와 include 디렉토리를 내 어플리케이션 프로젝트 최상위폴더 바로 아래에 openssl 폴더 생성 후 그곳에 복사 
예 : /MyApp/openssl/include, /MyApp/openssl/lib

3. xcode를 실행하여 프로젝트를 열고 buildsetting 의 Other Linker Flags 내용을 아래와 같이 수정
-Wl,-search_paths_first -lz -lcrypto -lssl

4. buildsetting 의 Header Search Paths  와 Library Search Paths  각각 맨 끝에 한칸 띄우고 아래 내용 추가 
Header Search Paths : {기존내용} $(SRCROOT)/openssl/include
Library Search Paths : {기존내용} $(SRCROOT)/openssl/lib

5. 소스 적용 ! (저는 압호화 결과를 base64로 인코딩하지 않고 16진수로 바꿔서 웹서버에 전달하였습니다., 상황에 맞게 수정하셔용 ~ ) 
#include <openssl/rsa.h>     // 이거 objective-c 에서 #import   문장있는곳에서 함께 사용 가능하니까 그냥 작성 하시면 됩니다. 
#include <openssl/evp.h>
#include <openssl/bn.h>

#include <openssl/pem.h>

- (NSString*) hexStringWithData: (unsigned char*) data ofLength: (NSUInteger) len
{
    NSMutableString *tmp = [NSMutableString string];
    for (NSUInteger i=0; i<len; i++)
        [tmp appendFormat:@"%02x", data[i]];
    return [NSString stringWithString:tmp];
}

-(NSString*)performRSAEncryptionForData:(NSString *)plaintext withModulus:(NSString*)mod andExponent:(NSString*)exp{
    
    //plaintext = @"abcd";
    
    NSMutableString *hexMod = [mod mutableCopy];
    NSMutableString *hexExp = [exp mutableCopy];
    
    const char *plain = [plaintext UTF8String];
    
    //char crip[]="";
    RSA * pubkey = RSA_new();
    BIGNUM * modul = BN_new();
    BIGNUM * expon = BN_new();
    
    BN_hex2bn(&modul, [hexMod UTF8String]);
    BN_hex2bn(&expon, [hexExp UTF8String]);
    
    
    pubkey->n = modul;
    pubkey->e = expon;
    
    int rsa_length = RSA_size(pubkey);
    unsigned char *crip[rsa_length];// =(unsigned char*)malloc( rsa_length ) ;
    //unsigned char *crip = (unsigned char*)malloc(rsa_length);
    
    
    NSString *s= [[NSString allocinit];
    //NSData* data;
    
    //int iRsaRet = RSA_public_encrypt(strlen(plain), (const unsigned char *) plain,  (unsigned char *)crip, pubkey, RSA_PKCS1_OAEP_PADDING );
    int iRsaRet = RSA_public_encrypt(strlen(plain), (const unsigned char *) plain,  (unsigned char *)crip, pubkey, RSA_PKCS1_PADDING );
    if (iRsaRet<=0)
    {
        NSLog(@"ERROR encrypt");
        s= @"";
    }
    else
    {
        NSLog(@"%lu",sizeof(crip));
        //data = [NSData dataWithBytes:crip length:sizeof(crip)];
        //data = [NSData dataWithBytes:(const void *)crip length:256];
        //s=[data base64Encoding];
        
        //암호화 결과를 16진수화
        s = [self hexStringWithData:crip ofLength:rsa_length];
        NSLog(@"Generated Token: %@",s);
        
    }
    
    return s;

}



=====================================================================
32bit 시절 적용햇던 내용

아.. 이것때문에 장장 2주동안 정말 계속 자료찾고 적용해보고 자료찾고 적용해보고.. 후아.. 
저처럼 고생하실수도있을 분들을 위해 작성해 봅니다. 

1. 주제 : IOS ( Objective-C) RSA 암호화  (RSA Encryption) 
2. 적용배경
  1) 키 생성  ( 웹서버 - Java) 
 - 로그인 암호화를 위해 웹서버에서 (java) RSA 공개키와 개인키를 만든다. 
 - 만들어진 공개키에서 Modulus 와 Exponent 를 뽑아낸다. 
   (이때 만들어진 modulus와 exponent 값은 16진수이다.  /  base64인코딩은 하지 않음)

  2) 키 수신 
  - 아이폰에서 암호화에 사용할 공개키 정보를 웹서버에 요청한다음 modulus와 exponent 값을 수신받는다. 
  
  3) 암호화
  - 수신받은 modulus와 exponent를 사용해서 암호화를 진행! 

----------------------------

사실 자바에서 RSA 키 생성하는 예제는 수도없이 많고 간단합니다. 
근데 여기서 난관에 봉착하게 되는것이 3번. 

IOS 에서 RSA 암호화 하는로직을 겁나 열심히 찾고 또찾아보고 
http://stackoverflow.com/ 여기를 2주동안 찾아해매도 제가 원하는 암호화 소스를 찾아내기가 너무 어려웠습니다. 

http://hhjeong.tistory.com/83  << 이 블로그에 있는 내용이 저와 적합한듯하여 적용해보고 싶었으나.. 아무리 소스를 돌려도 오류만 나고.. 
참조해주신 해더파일은 하나하나 찾아야했고.. 

암튼. 여담은 여기서 접고 본론으로 들어가겠습니다. 

------------------------------------

작업에 필요한 라이브러리 - openssl 
다운로드 위치 : https://code.google.com/p/ios-static-libraries/downloads/list
최신버전을 받으시면 될것 같습니다. 저는 ios-libraries-2011-03-10-065803.zip 을 내려받았습니다. 
1. 다운로드
2. 압축 해제
3. iPhoneOS-V7-4.3  디렉토리를  어플 프로젝트 최상위 디렉토리 아래에 복사 
4. Build Setting 메뉴료 이동 !   (다운로드받은 곳에 사용법도 나와잇으나.. 친절하게 적어드리자면! )
 - Header Search Path 항목에  ${SRCROOT}/iPhoneOS-V7-4.3/include  추가 
 - Library Search Path 항목에   ${SRCROOT}/iPhoneOS-V7-4.3/lib  추가 
 - Other Linker Flags 항목에        -Wl,-search_paths_first -lz -lcrypto -liconv -lsasl2 -letpan -lgcrypt -lgpg-error -lssh2 -lcurl   작성 

5. 소스 적용 ! (저는 압호화 결과를 base64로 인코딩하지 않고 16진수로 바꿔서 웹서버에 전달하였습니다., 상황에 맞게 수정하셔용 ~ ) 
#include <openssl/rsa.h>     // 이거 objective-c 에서 #import   문장있는곳에서 함께 사용 가능하니까 그냥 작성 하시면 됩니다. 
#include <openssl/evp.h>
#include <openssl/bn.h>

#include <openssl/pem.h>

- (NSString*) hexStringWithData: (unsigned char*) data ofLength: (NSUInteger) len
{
    NSMutableString *tmp = [NSMutableString string];
    for (NSUInteger i=0; i<len; i++)
        [tmp appendFormat:@"%02x", data[i]];
    return [NSString stringWithString:tmp];
}

-(NSString*)performRSAEncryptionForData:(NSString *)plaintext withModulus:(NSString*)mod andExponent:(NSString*)exp{
    
    //plaintext = @"abcd";
    
    NSMutableString *hexMod = [mod mutableCopy];
    NSMutableString *hexExp = [exp mutableCopy];
    
    const char *plain = [plaintext UTF8String];
    
    //char crip[]="";
    RSA * pubkey = RSA_new();
    BIGNUM * modul = BN_new();
    BIGNUM * expon = BN_new();
    
    BN_hex2bn(&modul, [hexMod UTF8String]);
    BN_hex2bn(&expon, [hexExp UTF8String]);
    
    
    pubkey->n = modul;
    pubkey->e = expon;
    
    int rsa_length = RSA_size(pubkey);
    unsigned char *crip[rsa_length];// =(unsigned char*)malloc( rsa_length ) ;
    //unsigned char *crip = (unsigned char*)malloc(rsa_length);
    
    
    NSString *s= [[NSString alloc] init];
    //NSData* data;
    
    //int iRsaRet = RSA_public_encrypt(strlen(plain), (const unsigned char *) plain,  (unsigned char *)crip, pubkey, RSA_PKCS1_OAEP_PADDING );
    int iRsaRet = RSA_public_encrypt(strlen(plain), (const unsigned char *) plain,  (unsigned char *)crip, pubkey, RSA_PKCS1_PADDING );
    if (iRsaRet<=0)
    {
        NSLog(@"ERROR encrypt");
        s= @"";
    }
    else
    {
        NSLog(@"%lu",sizeof(crip));
        //data = [NSData dataWithBytes:crip length:sizeof(crip)];
        //data = [NSData dataWithBytes:(const void *)crip length:256];
        //s=[data base64Encoding];
        
        //암호화 결과를 16진수화
        s = [self hexStringWithData:crip ofLength:rsa_length];
        NSLog(@"Generated Token: %@",s);
        
    }
    
    return s;

}

댓글