suroMind

[iPhone]Objective-C ~ Java AES 암호화 본문

IT분야/iOS

[iPhone]Objective-C ~ Java AES 암호화

suroMind 2011. 3. 24. 10:58

** Objective-c에서 데이터를 전송할 때 암호화가 필요할 때가 있다. 여러 다른 방법도 많이 있겠지만 AES를 통하여
  구현해봤다. 서버쪽은 자바기반이다. 출처는 구글신.. 여러 소스를 덕지덕지 모았다.

  key는 16자리로 하되 서버와 클라이언트에 같은 키를 넣어야한다. 대칭키이므로..

먼저 iPhone쪽 소스
=======================================================================================
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCryptor.h>


@interface AESExtention : NSObject {

}
- (NSString*) aesEncryptString:(NSString*)textString;

- (NSString*) aesDecryptString:(NSString*)textString;

- (NSData *)AES128EncryptWithKey:(NSString *)key theData:(NSData *)Data;

- (NSData *)AES128DecryptWithKey:(NSString *)key theData:(NSData *)Data;

-(NSString *)hexEncode:(NSData *)data;

- (NSData*) decodeHexString : (NSString *)hexString;
@end

========================================================================================
#import "AESExtention.h"

@implementation AESExtention

- (NSString*) aesEncryptString:(NSString*)textString{
    //NSString *text = [[NSString alloc] initWithString:@"ncdncd"];
    NSString *key = [NSString stringWithFormat:@"0987654321098765"];
   
    NSData *data = [[[NSData alloc] initWithData:[textString dataUsingEncoding:NSUTF8StringEncoding]]autorelease];
   
    NSData *ret = [self AES128EncryptWithKey:key theData:data];

    //NSLog(@"%@", [[AESExtention alloc] encodeHexString:ret]);
    return [self hexEncode:ret];
}

- (NSString*) aesDecryptString:(NSString*)textString{
    NSString *key = [NSString stringWithFormat:@"0987654321098765"];
    NSLog(@"hex = %@",textString);
    NSData *ret = [self decodeHexString:textString];
   
    NSData *ret2 = [self AES128DecryptWithKey:key theData:ret];
   
    NSString *st2 = [[[NSString alloc] initWithData:ret2 encoding:NSUTF8StringEncoding] autorelease];
   
    return st2;
}

- (NSData *)AES128EncryptWithKey:(NSString *)key theData:(NSData *)Data {
       
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused) // oorspronkelijk 256
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
   
    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
   
    NSUInteger dataLength = [Data length];
   
    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
   
    size_t numBytesEncrypted = 0;
   
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES128,
                                          kCCOptionECBMode +kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCKeySizeAES128, // oorspronkelijk 256
                                          nil, /* initialization vector (optional) */
                                          [Data bytes],
                                          dataLength, /* input */
                                          buffer,
                                          bufferSize, /* output */
                                          &numBytesEncrypted);
       
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
   
    free(buffer); //free the buffer;
    return nil;
}

- (NSData *)AES128DecryptWithKey:(NSString *)key theData:(NSData *)Data
{
   
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused) // oorspronkelijk 256
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
   
    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
   
    NSUInteger dataLength = [Data length];
   
    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
   
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES128,
                                          kCCOptionECBMode +kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES128, // oorspronkelijk 256
                                          NULL /* initialization vector (optional) */,
                                          [Data bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);
   
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }
   
    free(buffer); //free the buffer;
    return nil;
}

-(NSString *)hexEncode:(NSData *)data{
    NSMutableString *hex = [NSMutableString string];
    unsigned char *bytes = (unsigned char *)[data bytes];
    char temp[3];
    NSUInteger i=0;
   
    for(i=0; i<[data length]; i++){
        temp[0] = temp[1] = temp[2] =0;
        (void)sprintf(temp, "%02x",bytes[i]);
        [hex appendString:[NSString stringWithUTF8String:temp]];
       
    }
    return hex;
}

- (NSData*) decodeHexString : (NSString *)hexString
{
    int tlen = [hexString length]/2;
   
    char tbuf[tlen];
    int i,k,h,l;
    bzero(tbuf, sizeof(tbuf));
   
    for(i=0,k=0;i<tlen;i++)
    {
        h=[hexString characterAtIndex:k++];
        l=[hexString characterAtIndex:k++];
        h=(h >= 'A') ? h-'A'+10 : h-'0';
        l=(l >= 'A') ? l-'A'+10 : l-'0';
        tbuf[i]= ((h<<4)&0xf0)| (l&0x0f);
    }
   
    return [NSData dataWithBytes:tbuf length:tlen];
}

@end

===================================================================================================

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;

import org.apache.log4j.Logger;

public class AesUtil {
    Logger log = Logger.getRootLogger();
   
    public static String key = "0987654321098765";
   
    /**
     * hex to byte[] : 16진수 문자열을 바이트 배열로 변환한다.
     *
     * @param hex    hex string
     * @return
     */
    public static byte[] hexToByteArray(String hex) {
        if (hex == null || hex.length() == 0) {
            return null;
        }

        byte[] ba = new byte[hex.length() / 2];
        for (int i = 0; i < ba.length; i++) {
            ba[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
        }
        return ba;
    }

    /**
     * byte[] to hex : unsigned byte(바이트) 배열을 16진수 문자열로 바꾼다.
     *
     * @param ba        byte[]
     * @return
     */
    public static String byteArrayToHex(byte[] ba) {
        if (ba == null || ba.length == 0) {
            return null;
        }

        StringBuffer sb = new StringBuffer(ba.length * 2);
        String hexNumber;
        for (int x = 0; x < ba.length; x++) {
            hexNumber = "0" + Integer.toHexString(0xff & ba[x]);

            sb.append(hexNumber.substring(hexNumber.length() - 2));
        }
        return sb.toString();
    }

    /**
     * AES 방식의 암호화
     *
     * @param message
     * @return
     * @throws Exception
     */
    public static String encrypt(String message) throws Exception {
        //KeyGenerator kgen = KeyGenerator.getInstance("AES");
        //kgen.init(128);
        // use key coss2
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");

        // Instantiate the cipher
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

        byte[] encrypted = cipher.doFinal(message.getBytes());
        return byteArrayToHex(encrypted);
    }

    /**
     * AES 방식의 복호화
     *
     * @param message
     * @return
     * @throws Exception
     */
    public static String decrypt(String encrypted) throws Exception {
        //KeyGenerator kgen = KeyGenerator.getInstance("AES");
        //kgen.init(128);
        // use key coss2
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] original = cipher.doFinal(hexToByteArray(encrypted));
        String originalString = new String(original);
        return originalString;
    }
}

=================================================================================================

확실히 기억은 안나지만 1.5버전 이하는 자바폴더\jre\lib\security 쪽에 파일을 받아서 업데이트를 해주어야한다고 한다.
policy파일이던가.. 아무튼  전 1.6버전이라서 그런지 그냥 되더군요.

** 사용법**

-- Objective-c Encrypt
AESExtention *aes = [[AESExtention alloc] init];
NSString *temp = [NSString stringWithFormat:@"%@", [aes aesEncryptString:@"암호화할 문자열"]];
[aes release];

-- Objective-c Decrypt
AESExtention *aes = [[AESExtention alloc] init];
NSString *temp = [NSString stringWithFormat:@"%@", [aes aesDecryptString:@"복호화할 문자열"]];
[aes release];

-- Java
String token = AesUtil.encrypt("암호화할 문자열");
String token = AesUtil.decrypt("복호화할 문자열");

java쪽 필요한 lib
bcprov-ext-jdk16-145.jar
commons-io-1.4.jar
commons-lang-2.5.jar
log4j-1.2.16.jar
Comments