Cocos2d-xでOpenSSLを使う(Android編)

Android用にOpenSSLをビルドして使用する方法のメモ
※ パスはそれぞれ自分の環境に合わせてね

######実行した環境

+ OS X 10.10.3
+ Cocos2d-x v3.6
+ Android NDK r10d

### ソースコードをリポジトリからクローン
```bash
mkdir OpenSSL
cd OpenSSL
git clone -b OpenSSL_1_0_2a git://github.com/openssl/openssl.git src
```

### Android NDK Standalone Toolchainの作成
```bash
$NDK_ROOT/build/tools/make-standalone-toolchain.sh --arch=arm --install-dir=toolchain --platform=android-19
```

### ビルドする
###### armeabi
```bash
cd src
export ANDROID_DEV=$NDK_ROOT/platforms/android-19/arch-arm/usr
CROSS_COMPILE_PREFIX=/Users/ditabashi/OpenSSL/toolchain/bin/arm-linux-androideabi-
PREFIX=/Users/ditabashi/OpenSSL/dest/armeabi
./Configure --prefix=$PREFIX --cross-compile-prefix=$CROSS_COMPILE_PREFIX android threads no-shared
make -s && make install
```
###### armeabi-v7a
```bash
PREFIX=/Users/ditabashi/OpenSSL/dest/armeabi-v7a
make clean
./Configure --prefix=$PREFIX --cross-compile-prefix=$CROSS_COMPILE_PREFIX android-armv7 threads no-shared
make -s && make install
```

### Cocos2d-xプロジェクトに追加する
![openssl_path.png](https://qiita-image-store.s3.amazonaws.com/0/67518/d8a776fd-5b14-a2ee-630e-08e0473539b2.png "openssl_path.png")

###### Android.mkの中身
```Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/$(TARGET_ARCH_ABI)/include

LOCAL_MODULE := crypto
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/lib/libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)

LOCAL_MODULE := ssl
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/lib/libssl.a
include $(PREBUILT_STATIC_LIBRARY)

```

### プロジェクトのAndroid.mkを修正
```Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

$(call import-add-path,$(LOCAL_PATH)/../../cocos2d)
$(call import-add-path,$(LOCAL_PATH)/../../cocos2d/external)
$(call import-add-path,$(LOCAL_PATH)/../../cocos2d/cocos)

# **これを追加**
$(call import-add-path,$(LOCAL_PATH)/../../Libraries)

LOCAL_MODULE := cocos2dcpp_shared

LOCAL_MODULE_FILENAME := libcocos2dcpp

LOCAL_SRC_FILES := hellocpp/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   ../../Classes/HelloWorldScene.cpp

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes

# _COCOS_HEADER_ANDROID_BEGIN
# _COCOS_HEADER_ANDROID_END


LOCAL_STATIC_LIBRARIES := cocos2dx_static

# **これを追加**
LOCAL_STATIC_LIBRARIES += crypto ssl

# _COCOS_LIB_ANDROID_BEGIN
# _COCOS_LIB_ANDROID_END

include $(BUILD_SHARED_LIBRARY)

$(call import-module,.)

# _COCOS_LIB_IMPORT_ANDROID_BEGIN
# _COCOS_LIB_IMPORT_ANDROID_END

# **これを追加**
$(call import-module,OpenSSL/Android)

```

### 画像を暗号化してみる
```bash
openssl enc -e -aes-128-ecb -K 61616161616161616161616161616161 -in HelloWorld.png -out HelloWorld.dat
```
※ 61616161616161616161616161616161は"aaaaaaaaaaaaaaaa"の16進数表現

### 復号して表示する
```cpp:HelloWorldScene.cpp
#include <array>
#include <vector>
#include <openssl/evp.h>

cocos2d::Sprite *createSpriteFromEncryptedFile(const std::string &fileName) {
    static const std::array<unsigned char, 16> KEY = {'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
                                                      'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a'};

    auto fullPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(fileName);
    if (auto texture = cocos2d::Director::getInstance()->getTextureCache()->getTextureForKey(fullPath)) {
        return cocos2d::Sprite::createWithTexture(texture);
    }

    auto data = cocos2d::FileUtils::getInstance()->getDataFromFile(fullPath);

    EVP_CIPHER_CTX context;
    EVP_DecryptInit(&context, EVP_aes_128_ecb(), KEY.data(), nullptr);

    std::vector<unsigned char> buff(data.getSize());
    int len;
    int outLen = 0;
    if (!EVP_DecryptUpdate(&context, buff.data(), &len, data.getBytes(), static_cast<int>(data.getSize()))) {
        return nullptr;
    }
    outLen += len;

    if (!EVP_DecryptFinal(&context, buff.data() + len, &len)) {
        return nullptr;
    }
    outLen += len;

    cocos2d::Image image;
    image.initWithImageData(buff.data(), outLen);

    auto texture = cocos2d::Director::getInstance()->getTextureCache()->addImage(&image, fullPath);
    return cocos2d::Sprite::createWithTexture(texture);
}
```

```HelloWorldScene.cpp
    // add "HelloWorld" splash screen"
    auto sprite = createSpriteFromEncryptedFile("HelloWorld.dat");
    // auto sprite = Sprite::create("HelloWorld.png");
```

### おしまい
以上のことをまとめてシェルスクリプトにしてGitHubに置いておきました。
build-libssl-for-android.shを実行すれば同じ環境ならたぶん上手くいくはず。
https://github.com/idaisuke/hydrogenium/tree/master/build-tools/OpenSSL