HMAC SHA256

개발/Note 2020. 5. 28. 15:45
반응형

Examples of creating base64 hashes using HMAC SHA256 in different languages

21 Oct 2012

I recently went through the processing of creating SDKs for an in house API. The API required signing every REST request with HMAC SHA256 signatures. Those signatures then needed to be converted to base64. Amazon S3 uses base64 strings for their hashes. There are some good reasons to use base64 encoding. See the stackOverflow question What is the use of base 64 encoding?

Below are some simplified HMAC SHA 256 solutions. They should all output qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc= given the values of secret and Message. Take notice of the capital M. The hashed message is case sensitive.

Jump to an implementation:

Javascript HMAC SHA256

Run the code online with this jsfiddle. Dependent upon an open source js library called http://code.google.com/p/crypto-js/.

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script> <script> var hash = CryptoJS.HmacSHA256("Message", "secret"); var hashInBase64 = CryptoJS.enc.Base64.stringify(hash); document.write(hashInBase64); </script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script>

<script>
  var hash = CryptoJS.HmacSHA256("Message", "secret");
  var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
  document.write(hashInBase64);
</script>

PHP HMAC SHA256

PHP has built in methods for hash_hmac (PHP 5) and base64_encode (PHP 4, PHP 5) resulting in no outside dependencies. Say what you want about PHP but they have the cleanest code for this example.

$s = hash_hmac('sha256', 'Message', 'secret', true); echo base64_encode($s);

$s = hash_hmac('sha256', 'Message', 'secret', true);
echo base64_encode($s);

Java HMAC SHA256

Dependent on Apache Commons Codec to encode in base64.

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class ApiSecurityExample {
  public static void main(String[] args) {
    try {
     String secret = "secret";
     String message = "Message";

     Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
     SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
     sha256_HMAC.init(secret_key);

     String hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes()));
     System.out.println(hash);
    }
    catch (Exception e){
     System.out.println("Error");
    }
   }
}

Groovy HMAC SHA256

It is mostly java code but there are some slight differences. Adapted from Dev Takeout - Groovy HMAC/SHA256 representation.

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;

def hmac_sha256(String secretKey, String data) {
 try {
    Mac mac = Mac.getInstance("HmacSHA256")
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256")
    mac.init(secretKeySpec)
    byte[] digest = mac.doFinal(data.getBytes())
    return digest
   } catch (InvalidKeyException e) {
    throw new RuntimeException("Invalid key exception while converting to HMac SHA256")
  }
}

def hash = hmac_sha256("secret", "Message")
encodedData = hash.encodeBase64().toString()
log.info(encodedData)

C# HMAC SHA256

using System.Security.Cryptography;

namespace Test
{
  public class MyHmac
  {
    private string CreateToken(string message, string secret)
    {
      secret = secret ?? "";
      var encoding = new System.Text.ASCIIEncoding();
      byte[] keyByte = encoding.GetBytes(secret);
      byte[] messageBytes = encoding.GetBytes(message);
      using (var hmacsha256 = new HMACSHA256(keyByte))
      {
        byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
        return Convert.ToBase64String(hashmessage);
      }
    }
  }
}

Objective C and Cocoa HMAC SHA256

Most of the code required was for converting to bae64 and working the NSString and NSData data types.

#import "AppDelegate.h"
#import <CommonCrypto/CommonHMAC.h>

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
 NSString* key = @"secret";
 NSString* data = @"Message";

 const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
 const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
 unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
 CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
 NSData *hash = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];

 NSLog(@"%@", hash);

 NSString* s = [AppDelegate base64forData:hash];
 NSLog(s);
}

+ (NSString*)base64forData:(NSData*)theData {
 const uint8_t* input = (const uint8_t*)[theData bytes];
 NSInteger length = [theData length];

 static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

 NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
 uint8_t* output = (uint8_t*)data.mutableBytes;

 NSInteger i;
 for (i=0; i < length; i += 3) {
 NSInteger value = 0;
 NSInteger j;
 for (j = i; j < (i + 3); j++) {
 value <<= 8;

 if (j < length) {  value |= (0xFF & input[j]);  }  }  NSInteger theIndex = (i / 3) * 4;  output[theIndex + 0] = table[(value >> 18) & 0x3F];
 output[theIndex + 1] = table[(value >> 12) & 0x3F];
 output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
 output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
 }

 return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; }

@end

Go programming language - Golang HMAC SHA256

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "fmt"
)

func ComputeHmac256(message string, secret string) string {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func main() {
    fmt.Println(ComputeHmac256("Message", "secret"))
}

Ruby HMAC SHA256

Requires openssl and base64.

require 'openssl'
require "base64"

hash  = OpenSSL::HMAC.digest('sha256', "secret", "Message")
puts Base64.encode64(hash)

Python (2.7) HMAC SHA256

import hashlib
import hmac
import base64

message = bytes("Message").encode('utf-8')
secret = bytes("secret").encode('utf-8')

signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
print(signature)

Tested with Python 2.7.6. Also, be sure not to name your python demo script the same as one of the imported libraries.

Python (3.7) HMAC SHA256

import hashlib
import hmac
import base64

message = bytes('Message', 'utf-8')
secret = bytes('secret', 'utf-8')

signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
print(signature)

Tested with Python 3.7.0. Also, be sure not to name your python demo script the same as one of the imported libraries. Thanks to @biswapanda.

Perl HMAC SHA256

See Digest::SHA documentation. By convention, the Digest modules do not pad their Base64 output. To fix this you can test the length of the hash and append equal signs "=" until it is the length is a multiple of 4. We will use a modulus function below.

use Digest::SHA qw(hmac_sha256_base64);
$digest = hmac_sha256_base64("Message", "secret");

# digest is currently: qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc

# Fix padding of Base64 digests
while (length($digest) % 4) {
    $digest .= '=';
}

print $digest;
# digest is now: qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc=

Dart HMAC SHA256

Dependent upon the Dart crypto package.

import 'dart:html';
import 'dart:convert';
import 'package:crypto/crypto.dart';

void main() {

  String secret = 'secret';
  String message = 'Message';

  List<int> secretBytes = UTF8.encode('secret');
  List<int> messageBytes = UTF8.encode('Message');

  var hmac = new HMAC(new SHA256(), secretBytes);
  hmac.add(messageBytes);
  var digest = hmac.close();

  var hash = CryptoUtils.bytesToBase64(digest);

  // output to html page
  querySelector('#hash').text = hash;
  // hash => qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc=
}

Swift HMAC SHA256

I have not verified but see this stackOverflow post

Rust

Take a look at the alco/rust-digest repository for Rust (lang) guidance. I have not verified yet.

Powershell (Windows) HMAC SHA256

Mostly wrapping of .NET libraries but useful to see it in powershell's befuddling syntax. See code as gist

$message = 'Message'
$secret = 'secret'

$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
$signature = [Convert]::ToBase64String($signature)

echo $signature

# Do we get the expected signature?
echo ($signature -eq 'qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc=')

Shell (Bash etc) HMAC SHA256

Using openssl. Credit to @CzechJiri

MESSAGE="Message"
SECRET="secret"

echo -n $MESSAGE | openssl dgst -sha256 -hmac $SECRET -binary | base64

### Delphi HMAC SHA256

https://stackoverflow.com/a/40182566/215502

 

출처 : www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/

 

2020/12/16 - [개발노트] - Code 128 Barcode의 Check Digit 계산방법

2020/12/15 - [iOS/Tips] - 디버깅 차단 처리 (Anti Debug)

2020/12/14 - [iOS/Tips] - bundle id 알아내기

2020/12/12 - [AI/Algorithm] - 2D 충돌처리

2020/12/11 - [iOS/Swift] - UIViewController 스위칭

2020/12/11 - [개발노트] - PlantUML 설치 (Mac OS X)

2020/12/11 - [개발노트] - 특수문자 발음

2020/12/10 - [iOS/Objective-C] - 웹뷰에서 javascript 함수 동기식 호출

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (2/2)

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (1/2)

2020/12/10 - [iOS/Tips] - Custom UserAgent 설정

2020/12/10 - [iOS/Tips] - CocoaPods 설치 및 제거

2020/12/10 - [iOS/Tips] - Clang diagnostic 경고 무시하기

2020/12/10 - [개발노트] - Bluetooth UUID

2020/12/08 - [개발노트] - 모바일 앱 메모리덤프 이슈 해결방법

반응형

'개발 > Note' 카테고리의 다른 글

iPhone SDK location on hard drive  (0) 2020.05.29
HTTP Content-Type  (0) 2020.05.29
gdb 사용  (0) 2020.05.19
gdb 설치  (0) 2020.05.19
Mac에서 Node.js 설치  (0) 2020.05.19
블로그 이미지

SKY STORY

,

Array <-> Data 변환

개발/iOS 2020. 5. 26. 16:41
반응형
반응형

'개발 > iOS' 카테고리의 다른 글

NSString <-> CBUUID 변환  (0) 2020.05.29
SEED 블록암호 알고리즘 CBC (Cipher Block Chaining) 예제 (1/2)  (0) 2020.05.28
UserAgent 변경/추가  (0) 2020.05.25
RSA 암호화 / 복호화  (0) 2020.05.25
Base64 인코딩/디코딩  (0) 2020.05.25
블로그 이미지

SKY STORY

,

UserAgent 변경/추가

개발/iOS 2020. 5. 25. 17:58
반응형
let webConfiguration = WKWebViewConfiguration()
webConfiguration.applicationNameForUserAgent = "customize User-Agent"
let webView = WKWebView(frame: .zero, configuration: webConfiguration)

Output : Mozilla/5.0 (iPhone; CPU iPhone OS 11_2 like Mac OS X) AppleWebKit/604.4.7

(KHTML, like Gecko) customize User-Agent

 

let webView = WKWebView()
webView.evaluateJavaScript("navigator.userAgent") { (userAgent, error) in
    if let ua = userAgent {
        print("default WebView User-Agent > \(ua)")
    }

    // User-Agent에 '(my test)' 추가할 경우
    webView.customUserAgent = "\(ua) (my test)"
}

UserDefaults.standard.register(defaults: ["UserAgent": userAgentValue])

 

Output : Mozilla/5.0 (iPhone; CPU iPhone OS 11_2 like Mac OS X) AppleWebKit/604.4.7

(KHTML, like Gecko) customize User-Agent (my test)

 

 

 

반응형

'개발 > iOS' 카테고리의 다른 글

SEED 블록암호 알고리즘 CBC (Cipher Block Chaining) 예제 (1/2)  (0) 2020.05.28
Array <-> Data 변환  (0) 2020.05.26
RSA 암호화 / 복호화  (0) 2020.05.25
Base64 인코딩/디코딩  (0) 2020.05.25
Bitbucket Carthage 사용  (0) 2020.05.19
블로그 이미지

SKY STORY

,
반응형

RsaUtils 클래스를 생성하여 프로젝트에 추가한다.

//  RsaUtils.swift

import Foundation
import Security

public class RSAUtils {

    private static let PADDING_FOR_DECRYPT = SecPadding()

    @available(iOS, introduced: 1.2.0)
    public class RSAUtilsError: NSError {
        init(_ message: String) {
            super.init(domain: "com.ubpay.RSAUtils", code: 500, userInfo: [
                NSLocalizedDescriptionKey: message
            ])
        }

        @available(*, unavailable)
        required public init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }

    // Base64 encode a block of data
    @available(iOS, introduced: 1.2.0)
    private static func base64Encode(_ data: Data) -> String {
        return data.base64EncodedString(options: [])
    }

    // Base64 decode a base64-ed string
    @available(iOS, introduced: 1.2.0)
    private static func base64Decode(_ strBase64: String) -> Data {
        let data = Data(base64Encoded: strBase64, options: [])
        return data!
    }

    /**
     * Deletes an existing RSA key specified by a tag from keychain.
     *
     * - Parameter tagName: tag name to query for RSA key from keychain
     */
    @available(iOS, introduced: 1.2.0)
    public static func deleteRSAKeyFromKeychain(_ tagName: String) {
        let queryFilter: [String: AnyObject] = [
            String(kSecClass)             : kSecClassKey,
            String(kSecAttrKeyType)       : kSecAttrKeyTypeRSA,
            String(kSecAttrApplicationTag): tagName as AnyObject
        ]
        SecItemDelete(queryFilter as CFDictionary)
    }

    /**
     * Gets an existing RSA key specified by a tag from keychain.
     *
     * - Parameter tagName: tag name to query for RSA key from keychain
     *
     * - Returns: SecKey reference to the RSA key
     */
    @available(iOS, introduced: 1.2.0)
    public static func getRSAKeyFromKeychain(_ tagName: String) -> SecKey? {
        let queryFilter: [String: AnyObject] = [
            String(kSecClass)             : kSecClassKey,
            String(kSecAttrKeyType)       : kSecAttrKeyTypeRSA,
            String(kSecAttrApplicationTag): tagName as AnyObject,
            //String(kSecAttrAccessible)    : kSecAttrAccessibleWhenUnlocked,
            String(kSecReturnRef)         : true as AnyObject
        ]

        var keyPtr: AnyObject?
        let result = SecItemCopyMatching(queryFilter as CFDictionary, &keyPtr)
        if ( result != noErr || keyPtr == nil ) {
            return nil
        }
        return keyPtr as! SecKey?
    }

    /**
     * Adds a RSA private key (PKCS#1 or PKCS#8) to keychain and returns its SecKey reference.
     *
     * On disk, a PEM RSA PKCS#8 private key file starts with string "-----BEGIN PRIVATE KEY-----", and ends with string "-----END PRIVATE KEY-----"; PKCS#1 private key file starts with string "-----BEGIN RSA PRIVATE KEY-----", and ends with string "-----END RSA PRIVATE KEY-----".
     *
     * - Parameter privkeyBase64: RSA private key (PKCS#1 or PKCS#8) in base64
     * - Parameter tagName: tag name to store RSA key to keychain
     *
     * - Throws: `RSAUtilsError` if the input key is not a valid PKCS#8 private key
     *
     * - Returns: SecKey reference to the RSA private key.
     */
    @available(iOS, introduced: 1.2.0)
    @discardableResult public static func addRSAPrivateKey(_ privkeyBase64: String, tagName: String) throws -> SecKey? {
        let fullRange = NSRange(location: 0, length: privkeyBase64.lengthOfBytes(using: .utf8))
        let regExp = try! NSRegularExpression(pattern: "(-----BEGIN.*?-----)|(-----END.*?-----)|\\s+", options: [])
        let myPrivkeyBase64 = regExp.stringByReplacingMatches(in: privkeyBase64, options: [], range: fullRange, withTemplate: "")
        return try addRSAPrivateKey(base64Decode(myPrivkeyBase64), tagName: tagName)
    }

    /**
     * Adds a RSA private key to keychain and returns its SecKey reference.
     *
     * - Parameter privkey: RSA private key (PKCS#1 or PKCS#8)
     * - Parameter tagName: tag name to store RSA key to keychain
     *
     * - Throws: `RSAUtilsError` if the input key is not a valid PKCS#8 private key
     *
     * - Returns: SecKey reference to the RSA private key.
     */
    @available(iOS, introduced: 1.2.0)
    @discardableResult private static func addRSAPrivateKey(_ privkey: Data, tagName: String) throws -> SecKey? {
        // Delete any old lingering key with the same tag
        deleteRSAKeyFromKeychain(tagName)

        let privkeyData = try stripPrivateKeyHeader(privkey)
        if ( privkeyData == nil ) {
            return nil
        }

        // Add persistent version of the key to system keychain
        let queryFilter: [String : Any] = [
            (kSecClass as String)              : kSecClassKey,
            (kSecAttrKeyType as String)        : kSecAttrKeyTypeRSA,
            (kSecAttrApplicationTag as String) : tagName,
            //(kSecAttrAccessible as String)     : kSecAttrAccessibleWhenUnlocked,
            (kSecValueData as String)          : privkeyData!,
            (kSecAttrKeyClass as String)       : kSecAttrKeyClassPrivate,
            (kSecReturnPersistentRef as String): true
            ] as [String : Any]
        let result = SecItemAdd(queryFilter as CFDictionary, nil)
        if ((result != noErr) && (result != errSecDuplicateItem)) {
            NSLog("Cannot add key to keychain, status \(result).")
            return nil
        }

        return getRSAKeyFromKeychain(tagName)
    }

    /**
     * Verifies that the supplied key is in fact a PEM RSA private key, and strips its header.
     *
     * If the supplied key is PKCS#8, its ASN.1 header should be stripped. Otherwise (PKCS#1), the whole key data is left intact.
     *
     * On disk, a PEM RSA PKCS#8 private key file starts with string "-----BEGIN PRIVATE KEY-----", and ends with string "-----END PRIVATE KEY-----"; PKCS#1 private key file starts with string "-----BEGIN RSA PRIVATE KEY-----", and ends with string "-----END RSA PRIVATE KEY-----".
     *
     * - Parameter privkey: RSA private key (PKCS#1 or PKCS#8)
     *
     * - Throws: `RSAUtilsError` if the input key is not a valid RSA PKCS#8 private key
     *
     * - Returns: the RSA private key with header stripped.
     */
    @available(iOS, introduced: 1.2.0)
    private static func stripPrivateKeyHeader(_ privkey: Data) throws -> Data? {
        if ( privkey.count == 0 ) {
            return nil
        }

        var keyAsArray = [UInt8](repeating: 0, count: privkey.count / MemoryLayout<UInt8>.size)
        (privkey as NSData).getBytes(&keyAsArray, length: privkey.count)

        //PKCS#8: magic byte at offset 22, check if it's actually ASN.1
        var idx = 22
        if ( keyAsArray[idx] != 0x04 ) {
            return privkey
        }
        idx += 1

        //now we need to find out how long the key is, so we can extract the correct hunk
        //of bytes from the buffer.
        var len = Int(keyAsArray[idx])
        idx += 1
        let det = len & 0x80 //check if the high bit set
        if (det == 0) {
            //no? then the length of the key is a number that fits in one byte, (< 128)
            len = len & 0x7f
        } else {
            //otherwise, the length of the key is a number that doesn't fit in one byte (> 127)
            var byteCount = Int(len & 0x7f)
            if (byteCount + idx > privkey.count) {
                return nil
            }
            //so we need to snip off byteCount bytes from the front, and reverse their order
            var accum: UInt = 0
            var idx2 = idx
            idx += byteCount
            while (byteCount > 0) {
                //after each byte, we shove it over, accumulating the value into accum
                accum = (accum << 8) + UInt(keyAsArray[idx2])
                idx2 += 1
                byteCount -= 1
            }
            // now we have read all the bytes of the key length, and converted them to a number,
            // which is the number of bytes in the actual key.  we use this below to extract the
            // key bytes and operate on them
            len = Int(accum)
        }
        return privkey.subdata(in: idx..<idx+len)
        //return privkey.subdata(in: NSMakeRange(idx, len).toRange()!)
    }

    /**
     * Adds a RSA public key to keychain and returns its SecKey reference.
     *
     * - Parameter pubkeyBase64: X509 public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
     * - Parameter tagName: tag name to store RSA key to keychain
     *
     * - Throws: `RSAUtilsError` if the input key is indeed not a X509 public key
     *
     * - Returns: SecKey reference to the RSA public key.
     */
    @available(iOS, introduced: 1.2.0)
    public static func addRSAPublicKey(_ pubkeyBase64: String, tagName: String) throws -> SecKey? {
        let fullRange = NSRange(location: 0, length: pubkeyBase64.lengthOfBytes(using: .utf8))
        let regExp = try! NSRegularExpression(pattern: "(-----BEGIN.*?-----)|(-----END.*?-----)|\\s+", options: [])
        let myPubkeyBase64 = regExp.stringByReplacingMatches(in: pubkeyBase64, options: [], range: fullRange, withTemplate: "")
        return try addRSAPublicKey(base64Decode(myPubkeyBase64), tagName: tagName)
    }

    /**
     * Adds a RSA pubic key to keychain and returns its SecKey reference.
     *
     * - Parameter pubkey: X509 public key
     * - Parameter tagName: tag name to store RSA key to keychain
     *
     * - Throws: `RSAUtilsError` if the input key is not a valid X509 public key
     *
     * - Returns: SecKey reference to the RSA public key.
     */
    @available(iOS, introduced: 1.2.0)
    private static func addRSAPublicKey(_ pubkey: Data, tagName: String) throws -> SecKey? {
        // Delete any old lingering key with the same tag
        deleteRSAKeyFromKeychain(tagName)

        let pubkeyData = try stripPublicKeyHeader(pubkey)
        if ( pubkeyData == nil ) {
            return nil
        }

        // Add persistent version of the key to system keychain
        //var prt1: Unmanaged<AnyObject>?
        let queryFilter: [String : Any] = [
            (kSecClass as String)              : kSecClassKey,
            (kSecAttrKeyType as String)        : kSecAttrKeyTypeRSA,
            (kSecAttrApplicationTag as String) : tagName,
            (kSecValueData as String)          : pubkeyData!,
            (kSecAttrKeyClass as String)       : kSecAttrKeyClassPublic,
            (kSecReturnPersistentRef as String): true
            ] as [String : Any]
        let result = SecItemAdd(queryFilter as CFDictionary, nil)
        if ((result != noErr) && (result != errSecDuplicateItem)) {
            return nil
        }

        return getRSAKeyFromKeychain(tagName)
    }

    /**
     * Verifies that the supplied key is in fact a X509 public key, and strips its header.
     *
     * On disk, a X509 public key file starts with string "-----BEGIN PUBLIC KEY-----", and ends with string "-----END PUBLIC KEY-----"
     *
     * - Parameter pubkey: X509 public key
     *
     * - Throws: `RSAUtilsError` if the input key is not a valid X509 public key
     *
     * - Returns: the RSA public key with header stripped.
     */
    @available(iOS, introduced: 1.2.0)
    private static func stripPublicKeyHeader(_ pubkey: Data) throws -> Data? {
        if ( pubkey.count == 0 ) {
            return nil
        }

        var keyAsArray = [UInt8](repeating: 0, count: pubkey.count / MemoryLayout<UInt8>.size)
        (pubkey as NSData).getBytes(&keyAsArray, length: pubkey.count)

        var idx = 0
        if (keyAsArray[idx] != 0x30) {
            throw RSAUtilsError("Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30).")
            //return nil
        }
        idx += 1

        if (keyAsArray[idx] > 0x80) {
            idx += Int(keyAsArray[idx]) - 0x80 + 1
        } else {
            idx += 1
        }

        /*
         * If current byte is 0x02, it means the key doesn't have a X509 header (it contains only modulo & public exponent). In this case, we can just return the provided DER data as is
         */
        if (Int(keyAsArray[idx]) == 0x02) {
            return pubkey
        }

        let seqiod = [UInt8](arrayLiteral: 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00)
        for i in idx..<idx+seqiod.count {
            if ( keyAsArray[i] != seqiod[i-idx] ) {
                throw RSAUtilsError("Provided key doesn't have a valid X509 header.")
                //return nil
            }
        }
        idx += seqiod.count

        if (keyAsArray[idx] != 0x03) {
            throw RSAUtilsError("Invalid byte at index \(idx) (\(keyAsArray[idx])) for public key header.")
            //return nil
        }
        idx += 1

        if (keyAsArray[idx] > 0x80) {
            idx += Int(keyAsArray[idx]) - 0x80 + 1;
        } else {
            idx += 1
        }

        if (keyAsArray[idx] != 0x00) {
            throw RSAUtilsError("Invalid byte at index \(idx) (\(keyAsArray[idx])) for public key header.")
            //return nil
        }
        idx += 1
        return pubkey.subdata(in: idx..<keyAsArray.count)
        //return pubkey.subdata(in: NSMakeRange(idx, keyAsArray.count - idx).toRange()!)
    }

    /**
     * Encrypts data with a RSA key.
     *
     * - Parameter data: the data to be encrypted
     * - Parameter rsaKeyRef: the RSA key
     * - Parameter padding: padding used for encryption
     *
     * - Returns: the data in encrypted form
     */
    @available(iOS, introduced: 1.2.0)
    public static func encryptWithRSAKey(_ data: Data, rsaKeyRef: SecKey, padding: SecPadding) -> Data? {
        let blockSize = SecKeyGetBlockSize(rsaKeyRef)
        let dataSize = data.count / MemoryLayout<UInt8>.size
        let maxChunkSize = padding==SecPadding.OAEP ? (blockSize - 42) : (blockSize - 11)

        var dataAsArray = [UInt8](repeating: 0, count: dataSize)
        (data as NSData).getBytes(&dataAsArray, length: dataSize)

        var encryptedData = [UInt8](repeating: 0, count: 0)
        var idx = 0
        while (idx < dataAsArray.count ) {
            var idxEnd = idx + maxChunkSize
            if ( idxEnd > dataAsArray.count ) {
                idxEnd = dataAsArray.count
            }
            var chunkData = [UInt8](repeating: 0, count: maxChunkSize)
            for i in idx..<idxEnd {
                chunkData[i-idx] = dataAsArray[i]
            }

            var encryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
            var encryptedDataLength = blockSize

            let status = SecKeyEncrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &encryptedDataBuffer, &encryptedDataLength)
            if ( status != noErr ) {
                NSLog("Error while encrypting: %i", status)
                return nil
            }
            encryptedData += encryptedDataBuffer

            idx += maxChunkSize
        }

        return Data(bytes: UnsafePointer<UInt8>(encryptedData), count: encryptedData.count)
    }

    /**
     * Decrypts data with a RSA key.
     *
     * - Parameter encryptedData: the data to be decrypted
     * - Parameter rsaKeyRef: the RSA key
     * - Parameter padding: padding used for decryption
     *
     * - Returns: the decrypted data
     */
    @available(iOS, introduced: 1.2.0)
    public static func decryptWithRSAKey(_ encryptedData: Data, rsaKeyRef: SecKey, padding: SecPadding) -> Data? {
        let blockSize = SecKeyGetBlockSize(rsaKeyRef)
        let dataSize = encryptedData.count / MemoryLayout<UInt8>.size

        var encryptedDataAsArray = [UInt8](repeating: 0, count: dataSize)
        (encryptedData as NSData).getBytes(&encryptedDataAsArray, length: dataSize)

        var decryptedData = [UInt8](repeating: 0, count: 0)
        var idx = 0
        while (idx < encryptedDataAsArray.count ) {
            var idxEnd = idx + blockSize
            if ( idxEnd > encryptedDataAsArray.count ) {
                idxEnd = encryptedDataAsArray.count
            }
            var chunkData = [UInt8](repeating: 0, count: blockSize)
            for i in idx..<idxEnd {
                chunkData[i-idx] = encryptedDataAsArray[i]
            }

            var decryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
            var decryptedDataLength = blockSize

            let status = SecKeyDecrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &decryptedDataBuffer, &decryptedDataLength)
            if ( status != noErr ) {
                return nil
            }
            let finalData = removePadding(decryptedDataBuffer)
            decryptedData += finalData

            idx += blockSize
        }

        return Data(bytes: UnsafePointer<UInt8>(decryptedData), count: decryptedData.count)
    }

    @available(iOS, introduced: 1.2.0)
    private static func removePadding(_ data: [UInt8]) -> [UInt8] {
        var idxFirstZero = -1
        var idxNextZero = data.count
        for i in 0..<data.count {
            if ( data[i] == 0 ) {
                if ( idxFirstZero < 0 ) {
                    idxFirstZero = i
                } else {
                    idxNextZero = i
                    break
                }
            }
        }
        if ( idxNextZero-idxFirstZero-1 == 0 ) {
            idxNextZero = idxFirstZero
            idxFirstZero = -1
        }
        var newData = [UInt8](repeating: 0, count: idxNextZero-idxFirstZero-1)
        for i in idxFirstZero+1..<idxNextZero {
            newData[i-idxFirstZero-1] = data[i]
        }
        return newData
    }

    /**
     * Encrypts data using a RSA key from keychain specified by `tagName`.
     *
     * Note: The RSA key must be added to keychain by calling `addRSAPublicKey()` or `addRSAPrivateKey()` period to calling this function.
     *
     * - Parameter data: data to be encrypted
     * - Parameter tagName: tag name to query for RSA key from keychain.
     *
     * - Returns: the data in encrypted form
     */
    @available(iOS, introduced: 1.2.0)
    public static func encryptWithRSAKey(data: Data, tagName: String) -> Data? {
        let keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            return nil
        }

        return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
    }

    /**
     * Encrypts a string using a RSA key from keychain specified by `tagName`.
     *
     * Note: The RSA key must be added to keychain by calling `addRSAPublicKey()` or `addRSAPrivateKey()` period to calling this function.
     *
     * - Parameter str: string to be encrypted
     * - Parameter tagName: tag name to query for RSA key from keychain.
     *
     * - Returns: the data in encrypted form
     */
    @available(iOS, introduced: 1.2.0)
    public static func encryptWithRSAKey(str: String, tagName: String) -> Data? {
        let keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            return nil
        }

        return encryptWithRSAKey(str.data(using: .utf8)!, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
    }

    /**
     * Decrypts an encrypted data using a RSA key from keychain specified by `tagName`.
     *
     * Note: The RSA key must be added to keychain by calling `addRSAPublicKey()` or `addRSAPrivateKey()` period to calling this function.
     *
     * - Parameter encryptedData: data to be decrypted
     * - Parameter tagName: tag name to query for RSA key from keychain.
     *
     * - Returns: the decrypted data
     */
    @available(iOS, introduced: 1.2.0)
    public static func decryptWithRSAKey(encryptedData: Data, tagName: String) -> Data? {
        let keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            return nil
        }

        return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: PADDING_FOR_DECRYPT)
    }

    /*----------------------------------------------------------------------*/

    /**
     * Encrypts data using RSA public key.
     *
     * Note: the public key will be stored in keychain with tag as `pubkeyBase64.hashValue`.
     *
     * - Parameter data: data to be encrypted
     * - Parameter pubkeyBase64: X509 public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
     *
     * - Throws: `RSAUtilsError` if the supplied key is not a valid X509 public key
     *
     * - Returns: the data in encrypted form
     */
    @available(iOS, introduced: 1.2.0)
    public static func encryptWithRSAPublicKey(data: Data, pubkeyBase64: String) throws -> Data? {
        let tagName = "PUBIC-" + String(pubkeyBase64.hashValue)
        var keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            keyRef = try addRSAPublicKey(pubkeyBase64, tagName: tagName)
        }
        if ( keyRef == nil ) {
            return nil
        }

        return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
    }

    /**
     * Encrypts a string using RSA public key.
     *
     * Note: the public key will be stored in keychain with tag as `pubkeyBase64.hashValue`.
     *
     * - Parameter str: string to be encrypted
     * - Parameter pubkeyBase64: X509 public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
     *
     * - Throws: `RSAUtilsError` if the supplied key is not a valid X509 public key
     *
     * - Returns: the data in encrypted form
     */
    @available(iOS, introduced: 1.2.0)
    public static func encryptWithRSAPublicKey(str: String, pubkeyBase64: String) throws -> Data? {
        let tagName = "PUBIC-" + String(pubkeyBase64.hashValue)
        var keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            keyRef = try addRSAPublicKey(pubkeyBase64, tagName: tagName)
        }
        if ( keyRef == nil ) {
            return nil
        }

        return encryptWithRSAKey(str.data(using: .utf8)!, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
    }

    /**
     * Encrypts data using RSA public key.
     *
     * Note: the public key will be stored in keychain specified by tagName.
     *
     * - Parameter data: data to be encrypted
     * - Parameter pubkeyBase64: X509 public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
     * - Parameter tagName: tag name to store RSA key to keychain
     *
     * - Throws: `RSAUtilsError` if the supplied key is not a valid X509 public key
     *
     * - Returns: the data in encrypted form
     */
    @available(iOS, introduced: 1.2.0)
    public static func encryptWithRSAPublicKey(data: Data, pubkeyBase64: String, tagName: String) throws -> Data? {
        var keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            keyRef = try addRSAPublicKey(pubkeyBase64, tagName: tagName)
        }
        if ( keyRef == nil ) {
            return nil
        }

        return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
    }

    /**
     * Encrypts a string using RSA public key.
     *
     * Note: the public key will be stored in keychain specified by tagName.
     *
     * - Parameter str: string to be encrypted
     * - Parameter pubkeyBase64: X509 public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
     * - Parameter tagName: tag name to store RSA key to keychain
     *
     * - Throws: `RSAUtilsError` if the supplied key is not a valid X509 public key
     *
     * - Returns: the data in encrypted form
     */
    @available(iOS, introduced: 1.2.0)
    public static func encryptWithRSAPublicKey(str: String, pubkeyBase64: String, tagName: String) throws -> Data? {
        var keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            keyRef = try addRSAPublicKey(pubkeyBase64, tagName: tagName)
        }
        if ( keyRef == nil ) {
            return nil
        }

        return encryptWithRSAKey(str.data(using: .utf8)!, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
    }

    /*----------------------------------------------------------------------*/

    /**
     * Decrypts an encrypted data using a RSA private key.
     *
     * Note: the private key will be stored in keychain with tag as `privkeyBase64.hashValue`.
     *
     * - Parameter encryptedData: data to be decrypted
     * - Parameter privkeyBase64: RSA PKCS#8 private key in base64 (data between "-----BEGIN PRIVATE KEY-----" and "-----END PRIVATE KEY-----")
     *
     * - Throws: `RSAUtilsError` if the supplied key is not a valid RSA PKCS#8 private key
     *
     * - Returns: the decrypted data
     */
    @available(iOS, introduced: 1.2.0)
    public static func decryptWithRSAPrivateKey(encryptedData: Data, privkeyBase64: String) throws -> Data? {
        let tagName = "PRIVATE-" + String(privkeyBase64.hashValue)
        var keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            keyRef = try addRSAPrivateKey(privkeyBase64, tagName: tagName)
        }
        if ( keyRef == nil ) {
            return nil
        }

        return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: PADDING_FOR_DECRYPT)
    }

    /**
     * Decrypts an encrypted data using a RSA private key.
     *
     * Note: the private key will be stored in keychain specified by tagName.
     *
     * - Parameter encryptedData: data to be decrypted
     * - Parameter privkeyBase64: RSA PKCS#8 private key in base64 (data between "-----BEGIN PRIVATE KEY-----" and "-----END PRIVATE KEY-----")
     * - Parameter tagName: tag name to store RSA key to keychain
     *
     * - Throws: `RSAUtilsError` if the supplied key is not a valid RSA PKCS#8 private key
     *
     * - Returns: the data in encrypted form
     */
    @available(iOS, introduced: 1.2.0)
    public static func decryptWithRSAPrivateKey(encryptedData: Data, privkeyBase64: String, tagName: String) throws -> Data? {
        var keyRef = getRSAKeyFromKeychain(tagName)
        if ( keyRef == nil ) {
            keyRef = try addRSAPrivateKey(privkeyBase64, tagName: tagName)
        }
        if ( keyRef == nil ) {
            return nil
        }

        return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: PADDING_FOR_DECRYPT)
    }
}

 

RSA 키 생성은 아래 사이트에서 생성 및 테스트하였다.

https://8gwifi.org/RSAFunctionality?keysize=2048

 

테스트를 위해 생성된 키쌍은 다음과 같다.

Generate RSA Key Size :2048 bit

RSA Ciphers : RSA

Public Key :

-----BEGIN PUBLIC KEY-----

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk3EUep+Y0Ps8qumkNW8x

fvAEpill5SG/jBN3bJhwr6G5qpiC0g1ys4YcV9T0KKg2JBJIYFCHht4DH5GMyRxu

SWxh2lRC0mGJ38QVHBUGoJcbclCN3wsrUI9T+FhHN7TRL3YF+MzdbdMNultaCKq1

9KoPgYLo342rrfyvI9D51peed3CotaoQFAK7UqX/oggoP04OQ83fkSkZCu7T5uBG

b3ARjapwSEvvlC+A4E8WtqwjCx6YoE/XRa9iPAR5Fm0KUK2G8La0g9oUtG2dn+gL

iHkX00iI5PlIe0cFjPmKb5N75fLZNA9g0CkpVG2DrIGbdgp2CHD4Ufk3U99NSaH0

XwIDAQAB

-----END PUBLIC KEY-----

Private Key :

-----BEGIN RSA PRIVATE KEY-----

MIIEpAIBAAKCAQEAk3EUep+Y0Ps8qumkNW8xfvAEpill5SG/jBN3bJhwr6G5qpiC

0g1ys4YcV9T0KKg2JBJIYFCHht4DH5GMyRxuSWxh2lRC0mGJ38QVHBUGoJcbclCN

3wsrUI9T+FhHN7TRL3YF+MzdbdMNultaCKq19KoPgYLo342rrfyvI9D51peed3Co

taoQFAK7UqX/oggoP04OQ83fkSkZCu7T5uBGb3ARjapwSEvvlC+A4E8WtqwjCx6Y

oE/XRa9iPAR5Fm0KUK2G8La0g9oUtG2dn+gLiHkX00iI5PlIe0cFjPmKb5N75fLZ

NA9g0CkpVG2DrIGbdgp2CHD4Ufk3U99NSaH0XwIDAQABAoIBABCid28GRpV9YvDd

f1tP+kOaDMw6a3aYgiXppFWqNTx7gJkQr+HHBqPeg6AdNJbJs6IKNgQ30bKTpcKQ

B1RBUugRxFB/pTJbMtT+KGuMq7y+j6gsEnWRqwdhxFWGkDJmwhsas73IT0suvqPB

3ryPlgvOjAVOobtnHnF4ysG9uBJPyP03hCG97OIuHCQ0wpGlQAktyh7J5jXfGBJp

+bfOLGXZCqFO+iU0CRCf6si8/owTTXOYw7sANjtzbQt69GO+Vr3hi8SC2rGf/bkq

XFrajTOf1UC2wENKZJTY2H4cxedVViCMRThjMh5K1+661gKwUbSXyqN4jF4qsy/H

iAN/hgECgYEAyyf4dFhxjnTj7UiJtljqsF9seChqjtXHjHx0yq3wMCl+UMeMZ4Df

b5zOk9n4E6ntTEom4ZkUY+zYX+K4rR4W7FV5hhH/F5n+9BfXTludyPaQDWhpnaHw

1ZjQ8i7VMiYmy393Wd5sT5d1tDs4C1bvq10yAydKFV5a3bron8PsIt8CgYEAucsf

zQGtKb7emnDW4Cg61t1Bg/HXDxhm0EunP6gmTI+SUP/zZehg23xdajKYZ3zb3npm

Lz8LxGAxFIdp2o6BGgbTjotBTNlrza9Zh2H3BnV74TKS/gag3LfBtuRdZwhKgCPs

g4kkH4D1t6hza0Nql8cVjLvJnl++J+6YX3J53oECgYEAnIfvp7V9yYXHGM0LTrS0

H7Fmoi6B7AxL9LLwSjo7FuDhstwOErH5dsYbZVBNFNmZPW7lBm4sh9G15iuKn9jP

UMmLGQJEyqqdBvZXrshoiq9vzuTke9CLAAj+9ZugKUO8II/WJih6y9inmHcId7RE

doUYQ9XB/zT0TmP1WSRcjYECgYA37vDp9QE+uhmmASaPYU0ldoLMyDfocX4yYzQ8

s9Cj5+0yuXt7SJQwP6aX3BeJwEspFUxCGQbf3d2owoOZqqEvRrLWDRJhomsUByA6

48FMjn329BTQqQowqJmHCAUeiZ50KVyA1P6tBVP0MKBewHMMsoDIV5iBN22189yn

j30lAQKBgQCZoAR0wMlhcXqMt6GwlRDCrkBURyKy29sW+77AxXALPuxUGeEV0iBS

TFc8UUgmtMt7ZmaynukPThI7qtLXsNibVYFqENy1dF64SHIa1a0Qa0fBnhDqqWdk

oDeXJrKFS38ZGNfPpbPmI9Ti/7h2ct7WWWZAEtGO1buk7nZCxiOxig==

-----END RSA PRIVATE KEY-----

 

 

RSA Encode

// RSA Encode
let publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk3EUep+Y0Ps8qumkNW8xfvAEpill5SG/jBN3bJhwr6G5qpiC0g1ys4YcV9T0KKg2JBJIYFCHht4DH5GMyRxuSWxh2lRC0mGJ38QVHBUGoJcbclCN3wsrUI9T+FhHN7TRL3YF+MzdbdMNultaCKq19KoPgYLo342rrfyvI9D51peed3CotaoQFAK7UqX/oggoP04OQ83fkSkZCu7T5uBGb3ARjapwSEvvlC+A4E8WtqwjCx6YoE/XRa9iPAR5Fm0KUK2G8La0g9oUtG2dn+gLiHkX00iI5PlIe0cFjPmKb5N75fLZNA9g0CkpVG2DrIGbdgp2CHD4Ufk3U99NSaH0XwIDAQAB"

let string = "hello world"
//let data = string.data(using: .utf8)!
let encryptedData = try! RSAUtils.encryptWithRSAPublicKey(str: string, pubkeyBase64: publicKey)// Data
let encryptedString = (encryptedData!.base64EncodedString()) as String// Base64
print("\(encryptedString)")

Output: eDXn/2IJZYiCULVYR+IvmF6FVMvgU9YLVTnzDLlaXUJKib0FJy8Zhc2gJUZTtDtg4n48zVYU/jTL9UV0mpUls9jKScEBmm5lkR8qzV80skaAPTGnknYFg7nBtrsQPy2l1EUK0W9KaK1wN47JO/Si2Lyt9po3W2ErUFo1El3Gt/PdHTVpzftC64D+3iY/JU7YeHwBllPwEHQkY3hpgcVl4BxyNfbMCZuQXw5R8qiv5PObcKVliBYO7N4+5lXJXQoldMtGXzm+5G9M8xBgJDPJXzeqxl63o4AmG0ULKvhvHirHScOn0jvT5BEXM+oCkFm5SntQRt/iHtKCeIjqLE5eUg==

 

RSA Decode

let privateKey = "MIIEpAIBAAKCAQEAk3EUep+Y0Ps8qumkNW8xfvAEpill5SG/jBN3bJhwr6G5qpiC0g1ys4YcV9T0KKg2JBJIYFCHht4DH5GMyRxuSWxh2lRC0mGJ38QVHBUGoJcbclCN3wsrUI9T+FhHN7TRL3YF+MzdbdMNultaCKq19KoPgYLo342rrfyvI9D51peed3CotaoQFAK7UqX/oggoP04OQ83fkSkZCu7T5uBGb3ARjapwSEvvlC+A4E8WtqwjCx6YoE/XRa9iPAR5Fm0KUK2G8La0g9oUtG2dn+gLiHkX00iI5PlIe0cFjPmKb5N75fLZNA9g0CkpVG2DrIGbdgp2CHD4Ufk3U99NSaH0XwIDAQABAoIBABCid28GRpV9YvDdf1tP+kOaDMw6a3aYgiXppFWqNTx7gJkQr+HHBqPeg6AdNJbJs6IKNgQ30bKTpcKQB1RBUugRxFB/pTJbMtT+KGuMq7y+j6gsEnWRqwdhxFWGkDJmwhsas73IT0suvqPB3ryPlgvOjAVOobtnHnF4ysG9uBJPyP03hCG97OIuHCQ0wpGlQAktyh7J5jXfGBJp+bfOLGXZCqFO+iU0CRCf6si8/owTTXOYw7sANjtzbQt69GO+Vr3hi8SC2rGf/bkqXFrajTOf1UC2wENKZJTY2H4cxedVViCMRThjMh5K1+661gKwUbSXyqN4jF4qsy/HiAN/hgECgYEAyyf4dFhxjnTj7UiJtljqsF9seChqjtXHjHx0yq3wMCl+UMeMZ4Dfb5zOk9n4E6ntTEom4ZkUY+zYX+K4rR4W7FV5hhH/F5n+9BfXTludyPaQDWhpnaHw1ZjQ8i7VMiYmy393Wd5sT5d1tDs4C1bvq10yAydKFV5a3bron8PsIt8CgYEAucsfzQGtKb7emnDW4Cg61t1Bg/HXDxhm0EunP6gmTI+SUP/zZehg23xdajKYZ3zb3npmLz8LxGAxFIdp2o6BGgbTjotBTNlrza9Zh2H3BnV74TKS/gag3LfBtuRdZwhKgCPsg4kkH4D1t6hza0Nql8cVjLvJnl++J+6YX3J53oECgYEAnIfvp7V9yYXHGM0LTrS0H7Fmoi6B7AxL9LLwSjo7FuDhstwOErH5dsYbZVBNFNmZPW7lBm4sh9G15iuKn9jPUMmLGQJEyqqdBvZXrshoiq9vzuTke9CLAAj+9ZugKUO8II/WJih6y9inmHcId7REdoUYQ9XB/zT0TmP1WSRcjYECgYA37vDp9QE+uhmmASaPYU0ldoLMyDfocX4yYzQ8s9Cj5+0yuXt7SJQwP6aX3BeJwEspFUxCGQbf3d2owoOZqqEvRrLWDRJhomsUByA648FMjn329BTQqQowqJmHCAUeiZ50KVyA1P6tBVP0MKBewHMMsoDIV5iBN22189ynj30lAQKBgQCZoAR0wMlhcXqMt6GwlRDCrkBURyKy29sW+77AxXALPuxUGeEV0iBSTFc8UUgmtMt7ZmaynukPThI7qtLXsNibVYFqENy1dF64SHIa1a0Qa0fBnhDqqWdkoDeXJrKFS38ZGNfPpbPmI9Ti/7h2ct7WWWZAEtGO1buk7nZCxiOxig=="
        
let decryptedData = try! RSAUtils.decryptWithRSAPrivateKey(encryptedData: encryptedData!, privkeyBase64: privateKey)// Data
let decryptedString = String(data: decryptedData!, encoding: .utf8)
print("\(decryptedString)")

Output:  hello world

 

출처 : 

https://github.com/btnguyen2k/swiftutils/blob/master/SwiftUtils/RSAUtils.swift

 

2020/05/25 - [iOS/Swift] - Base64 인코딩/디코딩

2020/05/19 - [AI/Algorithm] - Generic algorithm

2020/05/19 - [AI/Algorithm] - neural network

2020/05/19 - [AI/Algorithm] - minimax full search example

2020/05/19 - [AI/Algorithm] - minimax, alpha-beta pruning

2020/05/19 - [iOS/Tips] - Bitbucket Carthage 사용

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/3) - 메모리 덤프

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/3) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/3) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

반응형

'개발 > iOS' 카테고리의 다른 글

Array <-> Data 변환  (0) 2020.05.26
UserAgent 변경/추가  (0) 2020.05.25
Base64 인코딩/디코딩  (0) 2020.05.25
Bitbucket Carthage 사용  (0) 2020.05.19
Fridump 사용법 (3/4) - 메모리 덤프  (0) 2020.05.19
블로그 이미지

SKY STORY

,
반응형

스마트폰 BTC 채굴앱

https://get.cryptobrowser.site/34473645

 

Earn coins while browsing the web

Earn bitcoins while watching videos, chatting, or playing online. It has never been so easy to increase your income! Tell your friends about CryptoTab Browser, invite them to join, and earn more together. Grow your network—get more profit!

get.cryptobrowser.site

 

// String을 Data로 변경
let string = "hello world"
let strData = string.data(using: .utf8)!

 

 

Base64 인코딩 / 디코딩 ( String )

// Base64 인코딩 ( Data -> Base64 encoded String )
let base64EncString = strData.base64EncodedString()

// Base64 디코딩 ( Base64 encoded String -> Base64 decoded String )
let decodedData = Data(base64Encoded: base64EncString)!
let base64DecString = String(data: decodedData, encoding: .utf8)!


print("Base64인코딩(String) : \(base64EncString)")
print("Base64디코딩(String) : \(base64DecString)")

 

 

Base64 인코딩 / 디코딩 ( Data )

// Base64 인코딩 ( Data -> Base64 encoded Data )
let base64EncData = strData.base64EncodedData(options: .lineLength64Characters)

// Base64 디코딩 ( Base64 encoded Data -> Base64 decoded Data )
let base64DecData = Data(base64Encoded: base64EncData, options: [])! as Data


print("Base64인코딩(Data) : \(String(data: base64EncData, encoding: .utf8)!)")
print("Base64디코딩(Data) : \(String(data: base64DecData, encoding: .utf8)!)")

 

스마트폰 BTC 채굴앱

https://get.cryptobrowser.site/34473645

 

Earn coins while browsing the web

Earn bitcoins while watching videos, chatting, or playing online. It has never been so easy to increase your income! Tell your friends about CryptoTab Browser, invite them to join, and earn more together. Grow your network—get more profit!

get.cryptobrowser.site

 

2020/05/25 - [iOS/Swift] - RSA 암호화 / 복호화

2020/05/19 - [AI/Algorithm] - Generic algorithm

2020/05/19 - [AI/Algorithm] - neural network

2020/05/19 - [AI/Algorithm] - minimax full search example

2020/05/19 - [AI/Algorithm] - minimax, alpha-beta pruning

2020/05/19 - [iOS/Tips] - Bitbucket Carthage 사용

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/3) - 메모리 덤프

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/3) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/3) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

반응형

'개발 > iOS' 카테고리의 다른 글

UserAgent 변경/추가  (0) 2020.05.25
RSA 암호화 / 복호화  (0) 2020.05.25
Bitbucket Carthage 사용  (0) 2020.05.19
Fridump 사용법 (3/4) - 메모리 덤프  (0) 2020.05.19
Fridump 사용법 (2/4) - Mac OS X 환경 구축  (0) 2020.05.19
블로그 이미지

SKY STORY

,
반응형

'Hello World!' 라는 문장을 유전자 알고림즘으로 찾아내는 셈플이다.

#ifndef ga_hpp
#define ga_hpp

#include <stdio.h>

#pragma warning(disable:4786) // disable debug warning

#include <iostream> // for cout etc.
#include <vector> // for vector class
#include <string> // for string class
#include <algorithm> // for sort algorithm
#include <time.h> // for random seed
#include <math.h> // for abs()


extern void go();


#endif /* ga_hpp */




//
//  ga.cpp
//  ga
//
//  Created by netcanis on 9/9/16.
//  Copyright © 2016 Netcanis. All rights reserved.
//

#include "ga.hpp"


// 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384

#define TOTAL_POPULATION    2048            // 총 인구     population size
#define MAXIUM_ITERATIONS   16384           // 최대 반복수  maximum iterations
#define ELITISM_RATE        0.10f           // 엘리티즘율   elitism rate
#define MUTATION_RATE       0.25f           // 변이율      mutation rate
#define MUTATION            RAND_MAX * MUTATION_RATE    // 변이 적용 숫자 (MUTATION_RATE에 대한 rand()값)
#define GA_TARGET           std::string("Hello world!") // 타겟 문장


using namespace std; // polluting global namespace, but hey...

struct Citizen
{
    string dna; // 유전자 정보
    unsigned int fitness; // its fitness
};

typedef vector<Citizen> CitizenArray;// 간결하기 위해 for brevity



// 인구 초기화
void initPopulation(CitizenArray &population, CitizenArray &buffer)
{
    for (int i=0; i<TOTAL_POPULATION; i++) {
        Citizen citizen;
        citizen.fitness = 0;
        citizen.dna.erase();
        
        // 문자열 범위안에서 랜덤하게 기본값을 넣어준다. (타겟 사이즈만큼 넣어준다)
        for (int j=0; j<GA_TARGET.size(); j++) {
            citizen.dna += (rand() % 90) + 32;
        }
        
        population.push_back(citizen);
    }
    
    buffer.resize(TOTAL_POPULATION);
}

// 적합도 계산
void calcFitness(CitizenArray &population)
{
    string target = GA_TARGET;
    int targetSize = (int)target.size();
    
    unsigned int fitness;
    for (int i=0; i<TOTAL_POPULATION; i++) {
        fitness = 0;
        for (int j=0; j<targetSize; j++) {
            fitness += abs(int(population[i].dna[j] - target[j]));
        }
        population[i].fitness = fitness;
    }
}

// 적합도 오름차순 정렬
bool sortFitness(Citizen x, Citizen y) {
    return (x.fitness < y.fitness);
}

inline void sortByFitness(CitizenArray &population) {
    sort(population.begin(), population.end(), sortFitness);
}

// 적합도 상위 엘리트를 버퍼에 저장한다.(재사용)
void elitism(CitizenArray &population, CitizenArray &buffer, int esize)
{
    for (int i=0; i<esize; i++) {
        buffer[i].dna = population[i].dna;
        buffer[i].fitness = population[i].fitness;
    }
}

// 두 dna를 반반 랜덤하게 섞는다.
string mixdna(string dna1, string dna2)
{
    string mdna;
    mdna.resize(GA_TARGET.size());
    for (int i=0; i<GA_TARGET.size(); ++i) {
        mdna[i] = (rand() % 2 == 0) ? dna1[i] : dna2[i];
    }
    return mdna;
}

// 변이
void mutate(Citizen &citizen)
{
    // 주어진 위치의 dna를 랜덤하게 바꾼다.
    int pos = rand() % GA_TARGET.size();
    citizen.dna[pos] = (rand() % 90) + 32;
}

// 교차
void mate(CitizenArray &population, CitizenArray &buffer)
{
    // 전체 인구에서 적합도 상위 주어진 퍼센티지만큼 적용했을때 계산된 인원수
    int eSize = TOTAL_POPULATION * ELITISM_RATE;
    
    // 주어진 적합도 상위 엘리트 시민은 교차를 적용하지 않고 그대로 버퍼에 추가한다.
    elitism(population, buffer, eSize);
    
    // Mate the rest
    // 엘리트들을 제외한 너머지 시민은 교차 실행
    for (int i = eSize; i < TOTAL_POPULATION; ++i) {
        // 전체 인구중 절반 상위 시민중 한명 선택 (상위 그룹)
        int index1 = rand() % (TOTAL_POPULATION / 2);
        // 전체 인구중 절반 하위 시민중 한명 선택 (하위 그룹)
        int index2 = rand() % (TOTAL_POPULATION / 2);
        
        string dna1 = population[index1].dna;
        string dna2 = population[index2].dna;
        
        // 50%확률로 랜덤하게 섞는다.
        buffer[i].dna = mixdna(dna1, dna2);
        
        // 변이 적용 - dna인자 한개를 랜덤하게 바꾸어 준다.
        if (rand() < MUTATION) {
            mutate(buffer[i]);
        }
    }
}

// 적합도가 가장 좋은 시민의 dna를 출력해준다.
inline void print_best(CitizenArray &citizen) {
    cout << "Best: " << citizen[0].dna << "  fitness = (" << citizen[0].fitness << ")" << endl;
}

// 대치
inline void swap(CitizenArray *&population, CitizenArray *&buffer) {
    CitizenArray *temp = population; population = buffer; buffer = temp;
}


void go()
{
    srand(unsigned(time(NULL)));
    
    CitizenArray pop_alpha;
    CitizenArray pop_beta;
    
    CitizenArray *population;
    CitizenArray *buffer;
    
    initPopulation(pop_alpha, pop_beta);
    population = &pop_alpha;
    buffer = &pop_beta;
    
    for (int i=0; i<MAXIUM_ITERATIONS; i++) {
        calcFitness(*population); // calculate fitness
        sortByFitness(*population);     // sort them
        print_best(*population); // print the best one
        
        // 적합도가 100%이면 종료처리한다.
        if ((*population)[0].fitness == 0) {
            break;
        }
        
        // 교차
        mate(*population, *buffer); // mate the population together
        
        // 대치
        swap(population, buffer); // swap buffers
    }
}
 

2020/05/19 - [AI/Algorithm] - neural network

2020/05/19 - [AI/Algorithm] - minimax full search example

2020/05/19 - [AI/Algorithm] - minimax, alpha-beta pruning

2020/05/19 - [iOS/Tips] - Bitbucket Carthage 사용

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/3) - 메모리 덤프

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/3) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/3) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Neural Network (XOR)  (0) 2022.11.18
2D 충돌처리  (0) 2020.12.12
neural network  (0) 2020.05.19
minimax full search example  (0) 2020.05.19
minimax, alpha-beta pruning  (0) 2020.05.19
블로그 이미지

SKY STORY

,
반응형

신경망 셈플 프로그램입니다.

 

#include <iostream>
#include <string>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <fstream>
using namespace std;


// 현재 네트워크의 학습률은 2의 제곱근
float learningRate = 1.414213562;

// 운동량
float momentum = 0.25;

// 바이어스(경향, 성향)
int bias = 1;


// 신경망을 통해 전달되는 학습 데이터
double arrTrainingData[4][2] = {
    { 1, 0 },   // target : 1
    { 1, 1 },   // target : 0
    { 0, 1 },   // target : 1
    { 0, 0 }    // target : 0
};

// 신경망 학습 데이터에 대한 값
int arrTargetData[4] = {
    1,
    0,
    1,
    0
};


// 신경망 가중치 값들
float arrWeight[9] = {};
// 신규 업데이트 가중치 값
float arrUpdateWeight[9];
// 이전 업데이트 가중치 값
float arrUpdatePrevWeight[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };

// Hidden Layer
float sumHiddenLayer1;
float sumHiddenLayer2;


// 편미분(도함수) 값
float derivativeOutput;
float derivativeHiddenLayer1;
float derivativeHiddenLayer2;
float sumOutput;

// 기울기(미분 값)
float gradients[9];

// 최종 결과 값
float outputNeuron;

// 현재 학습중인 세대
int epoch = 0;

// 에러
float arrError[4];
float arrRMSE[20000];






////////Prototyping////////
float sigmoid(float x);
void calcHiddenLayers(double input1, double input2);
void calcOutputNeuron();
void calcError(int x);
void calcDerivatives();
void backwardPropagation(double input1, double input2, float error);
void calcUpdates();
void update_new_arrWeight();
float calcRMSE();
void generateWeight();
void trainingNeuralNetwork();
void testInput();
void saveData();
////////Prototyping////////


int main(int argc, const char * argv[]) {
    
    /*
     input neurons : 2
     hidden layers : 2
     output neuron : 1
     
     The learning algorithm i use is the backpropagation algorithm.
     The network has 2 input neurons, 2 hidden layers, and 1 output neuron.
     also the hidden layer and the output layer is supported by a additional bias neuron(a neuron with a constant value of 1)
     */

    
    // 가중치 값 생성
    generateWeight();
    
    // 신경망 학습
    trainingNeuralNetwork();
    
    // 저장파일 생성
    saveData();
    
    // 입력 시작
    testInput();
    
    system("pause");
    
    return 0;
}


////////////////////////////////////////////////////////////////////////////////////////////////
// 가중치 값 랜덤 생성
void generateWeight()
{
    srand((unsigned)time(NULL));
    
    for (int i = 0; i < 9; i++)
    {
        if (1 == rand() % 2) {
            // generate number between -1.0 and 0.0
            arrWeight[i] = -(double(rand()) / (double(RAND_MAX) + 1.0));
        } else {
            // generate number between 1.0 and 0.0
            arrWeight[i] = double(rand()) / (double(RAND_MAX) + 1.0);
        }
        
        cout << "weight " << i << " = " << arrWeight[i] << endl;
    }
    cout << "" << endl;
}

// 신경망 학습
void trainingNeuralNetwork()
{
    // 20000 세대만큼 반복
    while (epoch < 20000)
    {
        for (int i = 0; i < 4; i++)
        {
            double input1 = arrTrainingData[i][0];
            double input2 = arrTrainingData[i][1];
            calcHiddenLayers(input1, input2);   // input
            calcOutputNeuron();                 // output
            
            
            calcError(i); // input!!
            
            calcDerivatives(); // input!!
            
            float error = arrError[i];
            backwardPropagation(input1, input2, error); // input!!
            
            calcUpdates();
            update_new_arrWeight();
        }
        
        // 제곱근 평균 제곱 오차(RMSE;오차(잔차)의 제곱에 대해 평균을 취하고 이를 제곱근한 것)
        // 작을수록 추정의 정확성이 높다.
        // 추정값들이 중심으로부터 얼마나 멀리 떨어져 있는지를 나타낼때 많이 쓰인다.
        float rmse = calcRMSE();
        arrRMSE[epoch] = rmse;
        cout << "epoch: " << epoch << endl;
        
        // 세대수 증가
        epoch = epoch + 1;
        
        
        
        // Adding some motivation so if the neural network is not converging after 4000 epochs it will start over again until it converges
        // 신경망이 4000세대 이후까지 RMSE 에러율이 0.5이하가 안된다면 처음부터 다시 시도한다.(가중치 재설정)
        if (epoch > 4000 && rmse > 0.5)
        {
            for (int i = 0; i < 9; i++)
            {
                arrUpdatePrevWeight[i] = 0;
                arrUpdateWeight[i] = 0;
                gradients[i] = 0;
            }
            for (int i = 0; i < 4; i++) {
                arrError[i] = 0;
            }
            for (int i = 0; i < epoch; i++) {
                arrRMSE[i] = 0;
            }
            epoch = 0;
            generateWeight();
        }
    }
}


// 저장 파일 생성
void saveData()
{
    // 각 세대별 RMSE값 저장
    ofstream dataER;
    dataER.open("errorData1.txt");
    for (int i = 0; i < epoch; i++)
    {
        dataER << i << "   " << arrRMSE[i] << endl;
    }
    dataER.close();
    
    // 최종 가중치 값 저장
    ofstream dataER1;
    dataER1.open("weight_data1.txt");
    for (int i = 0; i < 9; i++)
    {
        dataER1 << i << "   " << arrWeight[i] << endl;
    }
    dataER1.close();
}

// 학습된 신경망 테스트
void testInput()
{
    char choise = 'Y';

    do
    {
        if (choise == 'Y' || choise == 'y')
        {
            float input1;
            float input2;
            cout << "user input 1: "; cin >> input1; cout << endl;
            cout << "user input 2: "; cin >> input2; cout << endl;
            calcHiddenLayers(input1, input2);   // input
            calcOutputNeuron();                 // output
            
            // 반올림 처리로 최종 값을 결정 함
            cout << "output = " << outputNeuron << " => " << floor(outputNeuron+0.5) << endl;
            
            cout << "Again(y/n)? "; cin >> choise;
        }
        else
        {
            break;
        }
    } while ((choise == 'Y' || 'y') && (choise != 'n' || 'N'));
}

////////////////////////////////////////////////////////////////////////////////////////////////

/*
           bias(1)       bias(1)
             | \         |
             |  w4       w8
             |   \       |
 input1 --w0 --- h1      |
        \    |  /  \     |
         \    \/    w6   |
          w1  /\     \   |
            \/  \      outputNeuron
            /\   \    /
          w2  \   w5 w7
          /    \  | /
         /      \ |/
 input2 --w3----- h2
 */

// Hidden Layer 계산
void calcHiddenLayers(double input1, double input2)
{
    sumHiddenLayer1 = (input1 * arrWeight[0]) + (input2 * arrWeight[2]) + (bias * arrWeight[4]);
    sumHiddenLayer2 = (input1 * arrWeight[1]) + (input2 * arrWeight[3]) + (bias * arrWeight[5]);
}

// Output Layer 계산
void calcOutputNeuron()
{
    sumOutput = (sigmoid(sumHiddenLayer1) * arrWeight[6]) + (sigmoid(sumHiddenLayer2) * arrWeight[7]) + (bias * arrWeight[8]);
    outputNeuron = sigmoid(sumOutput);
}


// sigmoid activation function
// 계단형식의 함수를 미분이 가능하도록 곡선화를 해주는 함수이다.
// 주어진 값(x)에 대하여 0 ~ 1사이의 값으로 변환하여 반환해 준다.
// 이 함수를 사용하는 이유는 미분이 용이하기 때문이다. 이 함수의 미분 공식은 sigmoid(x)(1-sigmoid(x)) 이다.
float sigmoid(float x)
{
    float sigmoid = 1.0 / (1.0 + exp(-x));
    return sigmoid;
}

// 타겟값과 얼마나 차이가 나는지 배열에 저장
void calcError(int x)
{
    arrError[x] = outputNeuron - arrTargetData[x];
}



// sigmoid 미분
void calcDerivatives()
{
    /*
    derivativeOutput       = (exp(sumOutput)       / pow((1 + exp(sumOutput)),       2))  * -arrError[x];
    derivativeHiddenLayer1 = (exp(sumHiddenLayer1) / pow((1 + exp(sumHiddenLayer1)), 2))  *  arrWeight[6] * derivativeOutput;
    derivativeHiddenLayer2 = (exp(sumHiddenLayer2) / pow((1 + exp(sumHiddenLayer2)), 2))  *  arrWeight[7] * derivativeOutput;
    */

    // 각 출력값에대한 미분값을 구한다.
    derivativeOutput       = sigmoid(sumOutput)       * (1 - sigmoid(sumOutput));
    derivativeHiddenLayer1 = sigmoid(sumHiddenLayer1) * (1 - sigmoid(sumHiddenLayer1));
    derivativeHiddenLayer2 = sigmoid(sumHiddenLayer2) * (1 - sigmoid(sumHiddenLayer2));
}

// 기울기 계산
// Backward Propagation (역전파)
void backwardPropagation(double input1, double input2, float error)
{
    /*
    gradients[0] = sigmoid(input1) * derivativeHiddenLayer1;
    gradients[1] = sigmoid(input1) * derivativeHiddenLayer2;
    
    gradients[2] = sigmoid(input2) * derivativeHiddenLayer1;
    gradients[3] = sigmoid(input2) * derivativeHiddenLayer2;
    
    gradients[4] = sigmoid(bias)   * derivativeHiddenLayer1;
    gradients[5] = sigmoid(bias)   * derivativeHiddenLayer2;

    gradients[6] = sigmoid(sumHiddenLayer1) * derivativeOutput;
    gradients[7] = sigmoid(sumHiddenLayer2) * derivativeOutput;
    gradients[8] = sigmoid(bias)            * derivativeOutput;
     */

    
    
    // Backward Propagation(역전파)란 Error(오차)가 본래 진행방향과 반대방향으로 전파 된다고 하여 붙여진 이름이다.
    // 역전파 알고리즘은 Supervised Learning(input과 output을 알고있는 상태)에서 신경망을 학습시키는 방법이다.

    double bpOutput = derivativeOutput * -error;
    double bpLayer2 = derivativeHiddenLayer2 * arrWeight[7] * bpOutput;
    double bpLayer1 = derivativeHiddenLayer1 * arrWeight[6] * bpOutput;
    
    // w8,w7,w6
    gradients[8] = sigmoid(bias)            * bpOutput;
    gradients[7] = sigmoid(sumHiddenLayer2) * bpOutput;
    gradients[6] = sigmoid(sumHiddenLayer1) * bpOutput;
    
    // w5, w4
    gradients[5] = sigmoid(bias) * bpLayer2;
    gradients[4] = sigmoid(bias) * bpLayer1;
    
    // w3, w2
    gradients[3] = sigmoid(input2) * bpLayer2;
    gradients[2] = sigmoid(input2) * bpLayer1;
    
    // w1, w0
    gradients[1] = sigmoid(input1) * bpLayer2;
    gradients[0] = sigmoid(input1) * bpLayer1;
}

void calcUpdates()
{
    for (int i = 0; i < 9; i++)
    {
        //arrUpdateWeight[i] = gradients[i];
        arrUpdateWeight[i] = (learningRate * gradients[i]) + (momentum * arrUpdatePrevWeight[i]);
        
        arrUpdatePrevWeight[i] = arrUpdateWeight[i];
    }
}

void update_new_arrWeight()
{
    for (int i = 0; i < 9; i++)
    {
        arrWeight[i] = arrWeight[i] + arrUpdateWeight[i];
    }
}

float calcRMSE()
{
    float rmse = sqrt((pow(arrError[0], 2) + pow(arrError[1], 2) + pow(arrError[2], 2) + pow(arrError[3], 2) / 4));
    cout << "RMSE : " << rmse << endl;
    cout << "" << endl;
    return rmse;
}
 

2020/05/19 - [AI/Algorithm] - minimax full search example

2020/05/19 - [AI/Algorithm] - minimax, alpha-beta pruning

2020/05/19 - [iOS/Tips] - Bitbucket Carthage 사용

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/3) - 메모리 덤프

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/3) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/3) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

2020/05/18 - [iOS/Tips] - APNs

 

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Neural Network (XOR)  (0) 2022.11.18
2D 충돌처리  (0) 2020.12.12
Generic algorithm  (0) 2020.05.19
minimax full search example  (0) 2020.05.19
minimax, alpha-beta pruning  (0) 2020.05.19
블로그 이미지

SKY STORY

,
반응형

//  minimax full search example

 

#include <iostream>
#include <stdio.h>
#include <vector>

using namespace std;

// 가로 3, 세로 3 바둑판일 경우
// 0~8 총 9개의 자리가 있다. (자리 번호를 0번~8번이라 할경우)
// 내가 처음 놓는 자리를 정했을 때 컴퓨터와 번갈아 놓을 수 있는
// 모든 경우의 수를 minimax full search하여 출력한다.

// 0: empty,  1: human,  2: computer
int board[9] = {0,};
int numberOfCases = 0;


void printLog(int depth, int *log)
{
    for (int i=0; i<depth; ++i) {
        cout<<log[i];
        if (0 == i) {
            cout<<" -> ";
        } else {
            cout<<" ";
        }
    }
    cout<<endl;
}

bool isFull()
{
    for(int i=0; i<9; ++i) {
        if (board[i] == 0) {
            return false;
        }
    }
    return true;
}

int minimax(bool flag, int depth=1, int* log=nullptr)
{
    if(true == isFull()) {
        printLog(depth, log);
        numberOfCases ++;
        return 0;
    }
    
    for (int i = 0; i < 9; ++i) {
        if (board[i] != 0) continue;

        if(true == flag) {  // computer turn
            board[i] = 2;
            log[depth] = i;
            minimax(!flag, depth+1, &log[0]);
        } else {            // human turn
            board[i] = 1;
            log[depth] = i;
            minimax(!flag, depth+1, &log[0]);
        }
        board[i] = 0;
    }
    
    return 0;
}

int main(int argc, const char * argv[]) {

    cout<<"----------- minimax full search example ---------------"<<endl;
    
    int move;
    do {
        cout<<endl<<"Enter the move(0-8):";
        cin>>move;
    } while(move < 0 || move >= 9 || 0 != board[move]);
    
    board[move] = 1;
    
    vector<int> log(9, 0);
    log[0] = move;
    
    minimax(true, 1, &log[0]);

    cout << "number of cases : " << numberOfCases << endl;
    
    return 0;
}
 

2020/05/19 - [AI/Algorithm] - minimax, alpha-beta pruning

2020/05/19 - [iOS/Tips] - Bitbucket Carthage 사용

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/3) - 메모리 덤프

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/3) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/3) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

2020/05/18 - [iOS/Tips] - APNs

2020/05/18 - [iOS/Swift] - Multiple font colors in a single UILabel

 

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Neural Network (XOR)  (0) 2022.11.18
2D 충돌처리  (0) 2020.12.12
Generic algorithm  (0) 2020.05.19
neural network  (0) 2020.05.19
minimax, alpha-beta pruning  (0) 2020.05.19
블로그 이미지

SKY STORY

,
반응형

minimax, alpha-beta pruning

 

알고리즘 공부하면서 만들어봤던 tic tac toe 입니다.

 

 

// tic tac toe sample (minimax, alpha-beta pruning)

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>

using namespace std;


//#define TEST_MODE


// 0: 빈자리, 1:user, 2:computer
int board[9] = {0,};
// 화면에 출력할 문자
char shape[3] = {'*','O','X'};
// 컴퓨터가 놓은 수(배열 인덱스)
int target_index;
// 순서에 대한 인덱스
int sequence_index = 0;

#ifdef TEST_MODE
// 로그
int log[9] = {0,};
// 경우의 수
int numberOfCases = 0;
#endif//TEST_MODE


bool isFull();
int checkVictory(int index);
void printBoard();
#ifdef TEST_MODE
int minimax(bool flag, int index, int depth=1, int* log=nullptr);
#else
int minimax(bool flag, int index);
#endif//TEST_MODE
int alphaBetaPruning(bool flag, int* score);


#ifdef TEST_MODE
int fact_recursion(int n)
{
    if(n <= 1)
        return 1;
    else
        return n * fact_recursion(n-1);
}
#endif//TEST_MODE


// 놓을 곳이 있다면 0, 없다면 1을 리턴.
bool isFull()// Board is full
{
    for(int i=0; i<9; ++i ) {
        if (board[i] == 0) {
            return false;
        }
    }
    return true;
}

// 승리했을 경우 1, 그렇지 않으면 0 리턴
int checkVictory(int index)
{
//     0 1 2
//     3 4 5
//     6 7 8

    int x = index % 3;
    int y = index / 3;
    int r = board[y*3+x];
    
    // 가로
    if (board[y*3+0]==r && board[y*3+1]==r && board[y*3+2]==r)  return r;

    // 세로
    if (board[0*3+x]==r && board[1*3+x]==r && board[2*3+x]==r)  return r;

    // 대각선
    // 0,4,8 : 가로,세로,대각선\
    // 2,4,6 : 가로,세로,대각선/
    if(0 == index%4 && (board[0]==r && board[4]==r && board[8]==r))   return r;   /* 대각선 \ */
    if(0 == index%2 && (board[2]==r && board[4]==r && board[6]==r))   return r;   /* 대각선 / */
    
    return 0;
}

// 보드 상태 출력
void printBoard()
{
    cout<<endl;
    cout<<shape[board[0]]<<"|"<<shape[board[1]]<<"|"<<shape[board[2]]<<endl;
    cout<<"-----"<<endl;
    cout<<shape[board[3]]<<"|"<<shape[board[4]]<<"|"<<shape[board[5]]<<endl;
    cout<<"-----"<<endl;
    cout<<shape[board[6]]<<"|"<<shape[board[7]]<<"|"<<shape[board[8]]<<endl;
}


// 유저 수 두기
int doPlayer()
{
    int move;
    do {
        cout<<endl<<"Enter the move(0-8):";
        cin>>move;
    } while(move < 0 || move >= 9 || 0 != board[move]);
    
    
    // 순서 인덱스 증가
    sequence_index += 1;
    board[move] = 1;
    printBoard();
    
    
#ifdef TEST_MODE
    // 경우의 수 초기화
    numberOfCases = 0;
    
    // 로그 기록
    memset(&log[0], 0, sizeof(log));
    log[0] = move;
    
    cout<<endl<<sequence_index << "+ 유저의 선택 :" << move << endl;
#endif//TEST_MODE
    
    
    if (1 == checkVictory(move)) {
        cout<<endl<<"You Won......"<<endl<<endl;
        return 1;
    }
    
    if(true == isFull()) {
        cout<<endl<<"Draw...."<<endl<<endl;
        return 2;
    }
    
    return 0;
}

// 컴퓨터 수 두기
int doComputer() {
    
    cout<<endl<<"Computer Thinking..."<<endl;
    
    if (0 == sequence_index) {
        // 첫번째 두는 경우는 랜덤위치에 두도록 한다.
        target_index = rand() % 9;
    } else {
#ifdef TEST_MODE
        minimax(true, target_index, 1, &log[0]);
#else
        minimax(true, target_index);
#endif//TEST_MODE
    }
    
    cout<<endl<<"CPU MOVE...."<<endl;
    sequence_index += 1; // 순서 인덱스 증가
    board[target_index] = 2;
    printBoard();
    cout<<endl<< sequence_index << " + 컴퓨터의 선택 :" << target_index << endl;
    
#ifdef TEST_MODE
    int count = 0;
    for (int i=0; i<9; ++i) {
        if (0 == board[i]) count++;
    }
    int fact = fact_recursion(count+1);
    cout<<endl<< "number of cases : " << numberOfCases << endl;
    int cutoff = fact - numberOfCases;
    float per = (float)cutoff / (float)fact * 100.0;
    cout<<"total : "<<fact << ",   cutoff : "<< cutoff << " ("<< per << " %)"<<endl;
#endif//TEST_MODE
    
    if(2 == checkVictory(target_index)) {
        cout<<"CPU WON....."<<endl<<endl;
        return 1;
    }
    
    if(true == isFull()) {
        cout<<"Draw...."<<endl<<endl;
        return 2;
    }
    return 0;
}


#ifdef TEST_MODE

void printLog(int depth, int type)
{
    for (int i=0; i<depth; ++i) {
        cout<<log[i];
        if (0 == i) {
            cout<<" -> ";
        } else {
            cout<<" ";
        }
    }
    
    if (type == 10) {// 컴퓨터 승리
        cout << "\t\t depth : "<< depth <<" com won";
    } else if (type == -10) {// 인간 승리
        cout << "\t\t depth : "<< depth <<" human won";
    } else {// 무승부
        cout << "\t\t depth : "<< depth <<" draw";
    }
    cout<<endl;
    numberOfCases ++;
}

// minimax and alpha-beta pruning 알고리즘 구현
// flag가 true일경우 컴퓨터가 둘 차례, false이면 유저 차례
int minimax(bool flag, int index, int depth, int* log)
{
    int state = checkVictory(index);
    if(2 == state) {                // 컴퓨터가 이겻을 경우 10 리턴
        printLog(depth, 10);
        return 10;
    } else if(1 == state) {         // 유저가 이겼을 경우 -10 리턴
        printLog(depth, -10);
        return -10;
    } else if(true == isFull()) {   // 더이상 둘 자리가 없을 경우 0 리턴.
        printLog(depth, 0);
        return 0;
    }
    
    
    //if score[i]=1 then it is empty
    // 스코어 값이 1이면 빈자리를 의미한다.
    int score[9] = {1,1,1,1,1,1,1,1,1};
    
    for (int i = 0; i < 9; ++i) {
        // 빈 자리가 아니라면 스킵
        if (board[i] != 0) continue;
        
        int scoreValue = 1;
        
        if(true == flag) {
            // 컴퓨터가 가상으로 둔 수
            board[i] = 2;
            // 로그 기록
            log[depth] = i;
            // 유저가 둘 차례
            scoreValue = minimax(false, i, depth+1, &log[0]);
        } else {
            // 유저가 가상으로 둔 수
            board[i] = 1;
            // 로그 기록
            log[depth] = i;
            // 컴퓨터가 둘 차례
            scoreValue = minimax(true, i, depth+1, &log[0]);
        }
        
        // 가상으로 둔 수 초기화
        board[i] = 0;
        // 가상으로 둔 수에 대한 점수 기록.
        score[i] = scoreValue;
    }
    
    
    return alphaBetaPruning(flag, &score[0]);
}

#else

// minimax and alpha-beta pruning 알고리즘 구현
// flag가 true일경우 컴퓨터가 둘 차례, false이면 유저 차례
int minimax(bool flag, int index)
{
    //int checkVictory(int index)
    int state = checkVictory(index);
    if(2 == state) {                // 컴퓨터가 이겼을 경우 10 리턴
        return 10;
    } else if(1 == state) {         // 유저가 이겼을 경우 -10 리턴
        return -10;
    } else if(true == isFull()) {   // 더이상 둘 자리가 없을 경우 0 리턴.
        return 0;
    }
    
    
    //if score[i]=1 then it is empty
    // 스코어 값이 1이면 빈자리를 의미한다.
    int score[9] = {1,1,1,1,1,1,1,1,1};
    
    for (int i = 0; i < 9; ++i) {
        // 빈 자리가 아니라면 스킵
        if (board[i] != 0) continue;
        
        int scoreValue = 1;

        if(true == flag) {
            // 컴퓨터가 가상으로 둔 수
            board[i] = 2;
            // 유저가 둘 차례
            scoreValue = minimax(false, i);
        } else {
            // 유저가 가상으로 둔 수
            board[i] = 1;
            // 컴퓨터가 둘 차례
            scoreValue = minimax(true, i);
        }
        
        // 가상으로 둔 수 초기화
        board[i] = 0;
        // 가상으로 둔 수에 대한 점수 기록.
        score[i] = scoreValue;
    }
    
    return alphaBetaPruning(flag, &score[0]);
}
#endif//TEST_MODE


int alphaBetaPruning(bool flag, int* score)
{
    if (true == flag) {
        int maxValue = -1000;
        for (int j=0; j<9; ++j) {
            if(score[j] > maxValue && score[j] != 1) {
                maxValue = score[j];
                target_index = j;
            }
        }
        return maxValue;
    } else {
        int minValue = 1000;
        for(int j=0; j<9; ++j) {
            if(score[j] < minValue && score[j] != 1) {
                minValue = score[j];
                target_index = j;
            }
        }
        return minValue;
    }
}


int main(int argc, const char * argv[]) {

    srand((unsigned)time(0));
    
    cout<<"---------- TIC TAC TOE ----------";
    cout<<endl<<"Human : O,  Com : X";
    cout<<endl<<"Human first(1),  Com first(2) : ";
    int selectFirst;
    cin>>selectFirst;
    
    if(1 == selectFirst) {
        doPlayer();
    }
    
    while( true ) {
        if (doComputer() > 0) break;
        if (doPlayer() > 0) break;
    }
    
    return 0;
}

 

2020/05/19 - [AI/Algorithm] - minimax full search example

2020/05/19 - [iOS/Tips] - Bitbucket Carthage 사용

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/3) - 메모리 덤프

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/3) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/3) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

2020/05/18 - [iOS/Tips] - APNs

2020/05/18 - [iOS/Swift] - Multiple font colors in a single UILabel

 

반응형

'개발 > AI,ML,ALGORITHM' 카테고리의 다른 글

Neural Network (XOR)  (0) 2022.11.18
2D 충돌처리  (0) 2020.12.12
Generic algorithm  (0) 2020.05.19
neural network  (0) 2020.05.19
minimax full search example  (0) 2020.05.19
블로그 이미지

SKY STORY

,
반응형
반응형
블로그 이미지

SKY STORY

,
반응형

[ Mac OS X ] 메모리 덤프

테스트할 디바이스를 연결한 뒤 Fridump를 통해 메모리 덤프를 해보록 하겠습니다.

 

USB에 연결된 디바이스내 프로세스 이름과 PID목록 출력

frida-ps -U

 

 

만약 테스트하려는 앱이름이 한글일 경우

fridump.py파일을 열어 73번 라인 코드를 이름대신 PID값으로 처리되도록 다음과 같이 수정한 다.

 

아래와 같이 변경하면 입력한 앱이름대신 PID로 입력했을경우 입력된 PID문자열을 int형 변환을 통해 PID로 인식되어 처리되도록 한다.

session = frida.get_usb_device().attach(int(APP_NAME))

 

프로세스 이름으로 메모리 덤프 실행 ( 중요 : 관리자 권한 실행을 위해 -H옵션 추가)

sudo -H python fridump.py -U -s -r [앱이름] 

 

 

Finder에서 fridump폴더 아래 dump폴더가 생성된 것을 확인할 수 있다.

 

 

덤프 데이터파일 맨 아래 strings.txt파일을 볼 수 있다. 이것은 메모리내 문자열로 처리되어 검출된 데이터들을 모아놓은 텍스트 파일이다. 

(대부분 heap메모리 상에서 문자열 처리한 부분은 이곳에서 검출된다.)

 

 

strings.txt을 얼어보면 다음과같이 메모리에서 검출된 문자열정보들을 확인할 수 있다.

 

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/4) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/4) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/4) - 메모리 덤프

2020/06/12 - [iOS/Jailbreak] - Fridump 사용법 (4/4) - 결과물 바이너리 검색

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (1/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (2/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (3/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (4/4)

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

2020/05/18 - [iOS/etc] - APNs

2020/05/18 - [iOS/Swift] - Multiple font colors in a single UILabel

2020/05/18 - [개발툴/Xcode] - Storyboard References (스토리보드 분리)

2020/05/18 - [iOS/Jailbreak] - OpenSSL Mac 연동

2020/05/18 - [iOS/Objective-C] - NSLog 출력 크기 제한 풀기

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
블로그 이미지

SKY STORY

,
반응형

[ Mac OS X ] 환경 구축

Fridump를 사용한 메모리 덤프는 Mac OS X 환경에서 Fridump를 콘솔환경에서 실행하여 USB로 연결된 iOS디바이스에 실행중인 앱의 메모리를 덤프하게 됩니다.

이제 맥 환경구축을 해보도록 하겠습니다.

 

Homebrew 설치

https://brew.sh

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/ master/install)"

 

python 설치 (2.7.x버전이 설치되어 있음) - 아래 명령 실행시 python3 설치됨.(선택사항)

brew install python 

python —version

 

wget 설치

brew install wget

 

usbmuxd 설치

brew install usbmuxd rm get-pip.py

 

Xcode Command Line Tool 설치

xcode-select --install

 

MacPorts 다운로드 및 인스톨

https://www.macports.org/install.php

 

콘솔창 종료후 재실행

 

MacPort 설치

sudo port -v selfupdate

 

Putty 설치

sudo port install putty

 

pip설치

wget https://bootstrap.pypa.io/get-pip.py sudo python get-pip.py

 

Frida-tools 설치

sudo pip install frida-tools

 

'Cannot uninstall six' 에러 발생시 아래와 같이 처리한다.

sudo pip install frida-tools —ignore-installed six

 

버전문제로 인한 에러 처리

frida-tools 버전과 frida버전이 업데이트 되면서 서로 버전 지원 문제로

실행시 에러가 출력되며 실행되지 않는 경우가 있다.

탈옥 iPhone이 12.4버전일 경우 아래 버전으로 설치하기 바란다.

pip install frida==12.6.11

pip install frida-tools==2.0.2

 

실행중인 프로세스 이름과 PID 목록 출력

frida-ps

 

frada-ps 옵션을 확인

frida-ps -h

 

기기에서 실행중인 프로세스 목록 출력

frida-ps -U

-U : USB로 연결된 기기에 접속.

-D : Device ID로 기기에 접속.

-R : Remote Server(원격서버)에 접속

-H : Host의 Remote Server(원격서버)에 접속

 

USB에 연결된 디바이스 목록 출력

frida-ls-devices

 

기타 Frida관련 명령 및 사용법은 아래 사이트에서 참고하도록 한다.

https://www.frida.re/docs/ios/#with-jailbreak

 

 

fridump 설치

cd ~ 

git clone https://github.com/Nightbringer21/fridump

 

설치확인

cd fridump 

ls

 

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/4) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/4) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/4) - 메모리 덤프

2020/06/12 - [iOS/Jailbreak] - Fridump 사용법 (4/4) - 결과물 바이너리 검색

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (1/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (2/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (3/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (4/4)

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

2020/05/18 - [iOS/etc] - APNs

2020/05/18 - [iOS/Swift] - Multiple font colors in a single UILabel

2020/05/18 - [개발툴/Xcode] - Storyboard References (스토리보드 분리)

2020/05/18 - [iOS/Jailbreak] - OpenSSL Mac 연동

2020/05/18 - [iOS/Objective-C] - NSLog 출력 크기 제한 풀기

 

 

 

반응형
블로그 이미지

SKY STORY

,
반응형

[ iOS ] 환경 구축

iOS앱 메모리 덤프 Fridump 사용 방법에 대해 알아보겠습니다.

처음 해보는 경우 약간 복잡해 보일 수 있지만 최대한 쉽게 설명하도록 하겠습니다.

 

준비사항 :

⁃ jailbreak된 iOS Device (iPhone, iPad, iPod touch) 

⁃ Mac OS or Windows OS에 fridump, python, brew, pip, frida, frida-tools 등.

 

[ iOS Device ]

Cydia에서 OpenSSL, OpenSSH 설치

Cydia / Srouces 텝에서 다음 주소 추가 https://build.frida.re/

 

 

추가된 소스를 텝한다.

 

 

디바이스 비트수에 맞게 Frida 설치 (64bit일 경우 상단 Frida설치)

 

 

같은 방법으로 OpenSSL도 설치

 

 

OpenSSH, iFile, MobileTerminal등도 설치

 

 

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (1/4) - iOS디바이스 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (2/4) - Mac OS X 환경 구축

2020/05/19 - [iOS/Jailbreak] - Fridump 사용법 (3/4) - 메모리 덤프

2020/06/12 - [iOS/Jailbreak] - Fridump 사용법 (4/4) - 결과물 바이너리 검색

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (1/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (2/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (3/4)

2020/07/11 - [Android/Rooting] - 안드로이드 Fridump 사용하기 (4/4)

2020/05/19 - [iOS/Jailbreak] - Fridump, Tcpdump, OpenSSL Quick Guide

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

2020/05/18 - [iOS/etc] - APNs

2020/05/18 - [iOS/Swift] - Multiple font colors in a single UILabel

2020/05/18 - [개발툴/Xcode] - Storyboard References (스토리보드 분리)

2020/05/18 - [iOS/Jailbreak] - OpenSSL Mac 연동

2020/05/18 - [iOS/Objective-C] - NSLog 출력 크기 제한 풀기

 

 

 

 

 

 

 

반응형

'개발 > iOS' 카테고리의 다른 글

Fridump 사용법 (3/4) - 메모리 덤프  (0) 2020.05.19
Fridump 사용법 (2/4) - Mac OS X 환경 구축  (0) 2020.05.19
Fridump, Tcpdump, OpenSSL Quick Guide  (0) 2020.05.19
Frida 설치 및 사용법  (0) 2020.05.19
Tcpdump 사용법  (0) 2020.05.19
블로그 이미지

SKY STORY

,
반응형

[fridump 메모리 덤프]

frida-ps -Uai sudo -H python fridump.py -U -s -r

 

[Open SSL]

ssh netcanis@172.20.10.6

 

- 앱 설치 디랙토리 

/var/mobile/Containers/Data/Application 

 

- 앱 설치영역내 txt파일 검색 

find /var/mobile/Containers/Data/Application -name '*.txt' 

Ex) /var/mobile/Containers/Data/Application/6EB9B22F-45BA-4AF1-A540-B939713D9262/Library/ Caches/2019081909.txt

 

- text파일 읽기 

cap /var/mobile/Containers/Data/Application/6EB9B22F-45BA-4AF1-A540-B939713D9262/Library/ Caches/2019081909.txt

 

 

[tcpdump 리모트 패킷캡쳐]

주어진 UUID를 Virtual interface로 등록 

rvictl -s [UUID] 

rvictl -s 00008020-000915301AF2002E

 

등록된 virtual interface 이름 확인

rvictl -l

 

네트워크로 등록되어 있는지 확인된 이름으로 조회 

Ifconfig rvi0 

 

virtual interface를 삭제하려면 

rvictl -x [UUID] 

 

패킷캡쳐 

sudo tcpdump -n -i rvi0 

 

패킷캡쳐 (간략버전) 

sudo tcpdump -n -t -i rvi0 -q tcp 

 

패킷캡쳐 (아스키) 

sudo tcpdump -n -t -i rvi0 -q -A tcp

 

2020/05/19 - [OS/Mac OS X] - gdb 사용

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

2020/05/18 - [iOS/etc] - APNs

2020/05/18 - [iOS/Swift] - Multiple font colors in a single UILabel

2020/05/18 - [개발툴/Xcode] - Storyboard References (스토리보드 분리)

2020/05/18 - [iOS/Jailbreak] - OpenSSL Mac 연동

2020/05/18 - [iOS/Objective-C] - NSLog 출력 크기 제한 풀기

2020/05/18 - [OS/Mac OS X] - Symbolic Link

2020/05/18 - [개발툴/Xcode] - Release 모드에서 디버깅

2020/05/18 - [iOS/Jailbreak] - 탈옥후 안정화

2020/05/15 - [iOS/Swift] - 다중 문자열 / 캐릭터 제거

 

 

반응형

'개발 > iOS' 카테고리의 다른 글

Fridump 사용법 (2/4) - Mac OS X 환경 구축  (0) 2020.05.19
Fridump 사용법 (1/4) - iOS디바이스 환경 구축  (0) 2020.05.19
Frida 설치 및 사용법  (0) 2020.05.19
Tcpdump 사용법  (0) 2020.05.19
APNs - 기능 및 유실 사례  (0) 2020.05.18
블로그 이미지

SKY STORY

,

gdb 사용

개발/Note 2020. 5. 19. 11:15
반응형

gdb 사용

 

코드 작성

vi hello.m 

i 를 누르고 코딩

 

ESC를 눌러 insert모드를 초기화하고 :wq 를 타이핑해 저장 및 종료

 

hello.m 컴파일

gcc hello.m -o hello -g -l objc

 

생성된 파일 확인

ls -l

 

gdb실행파일 실행 

gdb ./hello

 

코드보기 (0번라인부터 출력)

l0

 

브레이크 포인트 설정

b7 

b8

 

실행시작 

 

계속 실행 및 종료

 

 

명령어

명령어 

의미 

 b (breakpoint)

 실행 중 디버그를 위해 멈추는 위치 지정

 b 함수명

 함수명에서 멈춤

 b 라인번호

 라인번호에서 멈춤

 r (run)

 실행 시작

 n (next)

 현재 라인 실행 (함수의 경우 실행하고 다음 라인으로 넘어 감)

 s (step)

 현재 라인 실행 (함수의 경우 호출된 함 수 내로 들어가 실행 계속)

 c (continue)

 다음 breakpoint까지 실행

 l (list)

 현재 수행되고 있는 라인부터 10개 라인 씩 연속적으로 소스 코드를 프린트

 p (print) 변수명

 변수명으로 저장되어 있는 내용을 프린 트

 h (help)

 도움말

 q (quit)  gdb 종료

 

참고:

http://muse.incheon.ac.kr/jschae/gcc_gdb.html 

http://kldp.org/node/71806 

http://boanchanggo.tistory.com/74

 

 

2020/05/19 - [iOS/Jailbreak] - Frida 설치 및 사용법

2020/05/19 - [OS/Mac OS X] - gdb 설치

2020/05/19 - [OS/Mac OS X] - Mac에서 Node.js 설치

2020/05/19 - [iOS/Jailbreak] - Tcpdump 사용법

2020/05/19 - [개발노트] - UUID의 구성 요소

2020/05/18 - [iOS/etc] - APNs

2020/05/18 - [iOS/Swift] - Multiple font colors in a single UILabel

2020/05/18 - [개발툴/Xcode] - Storyboard References (스토리보드 분리)

2020/05/18 - [iOS/Jailbreak] - OpenSSL Mac 연동

2020/05/18 - [iOS/Objective-C] - NSLog 출력 크기 제한 풀기

2020/05/18 - [OS/Mac OS X] - Symbolic Link

2020/05/18 - [개발툴/Xcode] - Release 모드에서 디버깅

2020/05/18 - [iOS/Jailbreak] - 탈옥후 안정화

2020/05/15 - [iOS/Swift] - 다중 문자열 / 캐릭터 제거

2020/05/15 - [iOS/Swift] - String substring

 

 

 

 

 

 

 

 

 

 

 

 

반응형

'개발 > Note' 카테고리의 다른 글

HTTP Content-Type  (0) 2020.05.29
HMAC SHA256  (0) 2020.05.28
gdb 설치  (0) 2020.05.19
Mac에서 Node.js 설치  (0) 2020.05.19
UUID의 구성 요소  (0) 2020.05.19
블로그 이미지

SKY STORY

,