/*
const char *str = (*env)->GetStringUTFChars(env, s, 0);
(*env)->ReleaseStringUTFChars(env, s, str);
*/

//string _jskey = static_cast<ostringstream*>( &(ostringstream() << _key) )->str();

/*

uint64_t features = android_getCpuFeatures();
if ((features & ANDROID_CPU_ARM_FEATURE_NEON) == 0) {
//NEON is not available
} else {
//NEON is available
}
int android_getCpuCount(void);

*/

#include "security.h"
#include "ParseEncryptAlgol.h"
#include "JniByteArrayWrapper.h"

#define sum32(x) (x += *(_readByte.operator->()))

#define shift_r32(_ex_num, _read_byt) nShift = (_ex_num > (SHA512_BLOCK_SIZE - _read_byt) ? \
_ex_num - (SHA512_BLOCK_SIZE - _read_byt) : \
(SHA512_BLOCK_SIZE - _read_byt) - _ex_num)

#define shift_l32(_ex_num, _read_byt) nShift = (_ex_num > (SHA512_ENDBYTE_BIGCAPS - _read_byt) ? \
_ex_num - (SHA512_ENDBYTE_BIGCAPS - _read_byt) : \
(SHA512_ENDBYTE_BIGCAPS - _read_byt) - _ex_num)

#define compile_num(i) ctx->hash_str[i] = encodingNum(_readByte.operator->());

#define compile_wbuf97(i) ctx->hash_str[i] = static_cast<char>(SHA512_START_DIGEST_BYTECODE_SMA LLCAPS + nShift);

#define compile_wbuf65(i) ctx->hash_str[i] = static_cast<char>(SHA512_START_DIGEST_BYTECODE_BIG CAPS + nShift);

#define compile_wbuf(i) ctx->hash_str[i] = static_cast<char>(*(_readByte.operator->()) + _extractKeyNum);

#define compile_dec_wbuf27(i) ctx->hash_str[i] = static_cast<char>(SHA512_SPACE_CHARBYTE);

#define compile_dec_num(i) ctx->hash_str[i] = decodingNum(_readByte.operator->());

#define compile_dec_wbuf65(i) ctx->hash_str[i] = static_cast<char>( SHA512_MASK - \
((*(_readByte.operator->()) - SHA512_STARTBYTE_CODEBIG_CAPS) > _extractKeyNum ? \
(*(_readByte.operator->()) - SHA512_STARTBYTE_CODEBIG_CAPS) - _extractKeyNum : \
_extractKeyNum - (*(_readByte.operator->()) - SHA512_STARTBYTE_CODEBIG_CAPS)) );

#define compile_dec_wbuf65_2(i) ctx->hash_str[i] = static_cast<char>(SHA512_BLOCK_SIZE - (_extractKeyNum - \
(*(_readByte.operator->()) - SHA512_START_DIGEST_BYTECODE_SMALLCAPS)));

#define compile_dec_wbuf97(i) ctx->hash_str[i] = static_cast<char>(nlShift);

#define compile_dec_wbuf(i) ctx->hash_str[i] = static_cast<char>(*(_readByte.operator->()) - _extractKeyNum);


using namespace BodyPowerNative;

jbyteArray security::encryptAlgol(JNIEnv *env, jobject j, jbyteArray jb) {


JniByteArrayWrapper *jniByteArrayWrapper = new JniByteArrayWrapper(env, jb);
jniByteArrayWrapper->parseJByteArray();
jbyteArray _encryptBytes = env->NewByteArray(jniByteArrayWrapper->get_lenHashData());
char *hash_str = new char[jniByteArrayWrapper->get_lenHashData()];
vector<char> vect = jniByteArrayWrapper->getVectorBytes();


/*
ParseEncryptAlgol* parseEncryptAlgol= new ParseEncryptAlgol(jniByteArrayWrapper);
transform(vect.begin(), vect.end(), hash_str,[](char byte){
return parseEncryptAlgol->evalAlgol(byte);
});*/

/*security sec;
int* p ;
p = reinterpret_cast<int*>(&sec);
char* c;
c = reinterpret_cast<char*>(&sec);
*/

jniByteArrayWrapper->encodingNum();

env->SetByteArrayRegion(_encryptBytes, 0, jniByteArrayWrapper->get_lenHashData(),
reinterpret_cast<const jbyte *>(hash_str));

delete[]hash_str;
delete jniByteArrayWrapper;

return _encryptBytes;
}

jbyteArray
SC::encrypt(JNIEnv *env, jobject jclazz, jbyteArray _data) {

try {

auto num_counter = 0;

auto _extractKeyNum = 0;

auto nShift = 0;

sha2_64t _key = 0;

sha1_32t _dataLength = env->GetArrayLength(_data);

if (_dataLength == 0)
throw Exp::getInstance();

unique_ptr<sha1_8> _readByte =
make_unique<sha1_8>();

if(!_readByte)
throw Exp::getInstance();

for (sha2_32t i = 0; i < _dataLength; ++i) {
env->GetByteArrayRegion(_data, i, 1, _readByte.get());
sum32(_key);
}

string _stringKey = NU::NumberToString(_key);

sha2_64t _sKeyLength = _stringKey.length();

int *_splitKeyNumArrays{new int[_sKeyLength]};
if(_splitKeyNumArrays == nullptr)
throw Exp::getInstance();

sha1_32t lenHashData = _dataLength + static_cast<int>(_sKeyLength);

sha512_ctx *ctx = new sha512_ctx(lenHashData);

jbyteArray _encryptBytes = env->NewByteArray(lenHashData);

splitKeyNum(_splitKeyNumArrays, _stringKey);

for (sha2_32t i = 0; i < _dataLength; ++i) {

if (num_counter >= _sKeyLength) {
num_counter = 0;
}
_extractKeyNum = _splitKeyNumArrays[num_counter++];

env->GetByteArrayRegion(_data, i, 1, _readByte.operator->());
jbyte jbRead = *(_readByte.operator->());

if (jbRead >= SHA512_STARTBYTECODE_NUMERIC &&
jbRead <= SHA512_ENDBYTE_CODE_NUMERIC) {

compile_num(i);

} else if (jbRead + _extractKeyNum > SHA512_BLOCK_SIZE) { //z 122

shift_r32(_extractKeyNum, jbRead);
compile_wbuf97(i);

} else if (jbRead + _extractKeyNum > SHA512_ENDBYTE_BIGCAPS &&
jbRead <= SHA512_ENDBYTE_BIGCAPS) { //Z 90

shift_l32(_extractKeyNum, jbRead);
compile_wbuf65(i);

} else {

compile_wbuf(i);

}
}

encodingNum(NU::NumberToString(_key), ctx->hash_str, _dataLength);

{
env->SetByteArrayRegion(_encryptBytes, 0, lenHashData,
reinterpret_cast<const jbyte *>(ctx->hash_str));

JniByteArrayWrapper *jniByteArrayWrapper;

revAlgol(env, _encryptBytes, jniByteArrayWrapper, ctx->hash_out);

env->SetByteArrayRegion(_encryptBytes, 0, jniByteArrayWrapper->get_lenHashData(),
reinterpret_cast<const jbyte *>(ctx->hash_out));
delete jniByteArrayWrapper;
jniByteArrayWrapper = nullptr;
}

_readByte.reset(); // delete smart pointer
//delete _readByte.operator->();
delete[]_splitKeyNumArrays;
delete ctx;
env->DeleteLocalRef(_data);
_splitKeyNumArrays = nullptr;

return _encryptBytes;
} catch (exception &E) {
static_cast<Exp &>(E).printStackTrace(E.what());
}

return nullptr;
}

void
SC::revAlgol(JNIEnv *&env, _jbyteArray *_encryptBytes,
JniByteArrayWrapper *&jbw, char *&hash_out) {

jbw = new JniByteArrayWrapper(env, _encryptBytes);
jbw->parseJByteArray();

hash_out = new char[jbw->get_lenHashData()];

vector<char> vect = jbw->getVectorBytes();

transform(vect.rbegin(), vect.rend(), hash_out, [&](char byte) {
//__android_log_print(ANDROID_LOG_ERROR,TAG_LOG_ANDR OID,"this lambda -> %lu" ,jbw->get_key());
return byte;
});
}


void
SC::revAlgol(JNIEnv *&env, _jbyteArray *_encryptBytes,
JniByteArrayWrapper *&jbw, char *&hash_str, jbyteArray &_encryptBytes_dest) {

revAlgol(env, _encryptBytes, jbw, hash_str);

_encryptBytes_dest = env->NewByteArray(jbw->get_lenHashData());

env->SetByteArrayRegion(_encryptBytes_dest, 0, jbw->get_lenHashData(),
reinterpret_cast<const jbyte *>(hash_str));
}

char
SC::encodingNum(const jbyte * _keyIter) {
char shiftNum;

try {
shiftNum = static_cast<char>(*(_keyIter) - SHA512_LEFT_SIDESHIFT);
} catch (exception &E) {
static_cast<Exp &>(E).printStackTrace(E.what());
}

return shiftNum;
}

char
SC::encodingNum(const char byte) {
char shiftNum;

try {
shiftNum = static_cast<char>(byte - SHA512_LEFT_SIDESHIFT);
} catch (exception &E) {
static_cast<Exp &>(E).printStackTrace(E.what());
}

return shiftNum;
}

char
SC::decodingNum(const jbyte *_keyIter) {

char shiftNum;
try {
shiftNum = static_cast<char>(*(_keyIter) + SHA512_LEFT_SIDESHIFT);
} catch (exception &E) {
static_cast<Exp &>(E).printStackTrace(E.what());
}

return shiftNum;
}

void
SC::encodingNum(string strNum, char *&hash_str, jsize len) {

try {

for (string::iterator _keyIter = strNum.begin();
_keyIter != strNum.end(); ++_keyIter) {

if (*(_keyIter) >= SHA512_STARTBYTECODE_NUMERIC &&
*(_keyIter) <= SHA512_ENDBYTE_CODE_NUMERIC) {

char shiftNum = static_cast<char>(*(_keyIter) - SHA512_LEFT_SIDESHIFT);
hash_str[len++] = shiftNum;
}
}

} catch (exception &E) {
static_cast<Exp &>(E).printStackTrace(E.what());
}

}

string
security::decodingNum(JNIEnv *env, const jbyteArray &_data) {

try {

jsize _dataLength = env->GetArrayLength(_data);

unique_ptr<jbyte> _readByte =
make_unique<jbyte>();
if(!_readByte)
throw Exp::getInstance();

string shiftNum;

char numChar;

//sum all bytes.
posSepChar = getEndReadBytePos(env, _data, _dataLength);

for (u_int _k = _dataLength - posSepChar; _k < _dataLength; ++_k) {
env->GetByteArrayRegion(_data, _k, 1, _readByte.operator->());

if (*(_readByte.operator->()) >= (SHA512_STARTBYTECODE_NUMERIC - SHA512_LEFT_SIDESHIFT)
&& *(_readByte.operator->()) <= (SHA512_ENDBYTE_CODE_NUMERIC - SHA512_LEFT_SIDESHIFT)) {

numChar = static_cast<char>(*(_readByte.operator->()) + SHA512_LEFT_SIDESHIFT);
shiftNum += numChar;

}

}

_readByte.release();
delete _readByte.operator->();

return shiftNum;

} catch (exception &E) {
static_cast<Exp &>(E).printStackTrace(E.what());
}

return nullptr;
}

u_int
SC::getEndReadBytePos(JNIEnv *env, const jbyteArray &_data, jsize _dataLength) {

sha2_64t _key = 0;

unique_ptr<jbyte> _readByte =
make_unique<jbyte>();

if(!_readByte)
throw Exp::getInstance();

for (u_int i = 0; i < _dataLength; ++i) {
env->GetByteArrayRegion(_data, i, 1, _readByte.operator->());
sum32(_key);
}

_readByte.reset(); // delete smart pointer
//delete _readByte.operator->();

return static_cast<u_int>(NU::NumberToString(_key).length ());
}

jbyteArray
SC::decrypt(JNIEnv *env, jobject jclazz, jbyteArray _encryptData) {

try {

jbyteArray _encryptBytes2;

{
JniByteArrayWrapper *jniByteArrayWrapper;

char *hash_in;

revAlgol(env, _encryptData, jniByteArrayWrapper, hash_in, _encryptBytes2);

delete[]hash_in;
hash_in= nullptr;
delete jniByteArrayWrapper;
jniByteArrayWrapper= nullptr;
}

string _stringKey = decodingNum(env, _encryptBytes2);

auto num_counter = 0;

auto _extractKeyNum = 0;

unique_ptr<jbyte> _readByte =
make_unique<jbyte>();
if(!_readByte)
throw Exp::getInstance();

jsize _dataLength = env->GetArrayLength(_encryptBytes2);

if (_dataLength == 0)
throw Exp::instance();

auto _orginalSizeOfHashArrays = _dataLength - posSepChar;

sha512_ctx *ctx = new sha512_ctx(_orginalSizeOfHashArrays);

jbyteArray _encryptBytes = env->NewByteArray(_orginalSizeOfHashArrays);

auto _keyLen = _stringKey.length();

int *_splitKeyNumArrays = new int[_keyLen];

splitKeyNum(_splitKeyNumArrays, _stringKey);

for (u_int i = 0; i < _dataLength - posSepChar; ++i) {

if (i >= _dataLength - posSepChar) {

compile_dec_wbuf27(i);

} else {

if (num_counter < _keyLen) {
_extractKeyNum = _splitKeyNumArrays[num_counter++];
} else {
num_counter = 0;
_extractKeyNum = _splitKeyNumArrays[num_counter++];
}

env->GetByteArrayRegion(_encryptBytes2, i, 1, _readByte.operator->());
jbyte jbRead = *(_readByte.operator->());

if (jbRead >= (SHA512_STARTBYTECODE_NUMERIC - SHA512_LEFT_SIDESHIFT)
&& jbRead <= (SHA512_ENDBYTE_CODE_NUMERIC - SHA512_LEFT_SIDESHIFT)) {

compile_dec_num(i);

} else if (jbRead < SHA512_MASK &&
jbRead - _extractKeyNum <= SHA512_ENDBYTE_BIGCAPS) {

auto nlShift = jbRead - _extractKeyNum;

if (nlShift <= SHA512_START_DIGEST_BYTECODE_BIGCAPS) {

compile_dec_wbuf65(i);

} else {

compile_dec_wbuf97(i);

}
} else if (*(_readByte.get()) - _extractKeyNum < SHA512_STARTBYTE_CODESMALL_CAPS) {

compile_dec_wbuf65_2(i);
} else {

compile_dec_wbuf(i);

}
}
}

env->SetByteArrayRegion(_encryptBytes, 0, _orginalSizeOfHashArrays,
reinterpret_cast<const jbyte *>(ctx->hash_str));

_readByte.release();
delete _readByte.operator->();
delete[]_splitKeyNumArrays;
delete ctx;
env->DeleteLocalRef(_encryptBytes2);
env->DeleteLocalRef(_encryptData);
_splitKeyNumArrays= nullptr;

return _encryptBytes;

} catch (exception &E) {
static_cast<Exp &>(E).printStackTrace(E.what());
}

return nullptr;
}


void
SC::splitKeyNum(int *&_splitKeyNumArrays, const string &_stringKey) {

try {

auto _sCounter = 0;
string str_num ;

for(auto const _key : _stringKey){
str_num = NU::NumberToString(_key);
*(_splitKeyNumArrays+_sCounter++) = NU::StringToNumber<int>(str_num);
}

} catch (exception &E) {
static_cast<Exp &>(E).printStackTrace(E.what());
}

}

jint
SC::customRand(JNIEnv *env, jobject jclazz, jint total, jint total_draw) {

/* if (total < total_draw)
return 0;

srand(static_cast<u_int>(time(NULL))); // create the seeds

u_int *balls =
new u_int[static_cast<u_int>(total_draw)]; // create new array

for (u_int i = 0; i < total_draw; i++) {
balls[i] = static_cast<u_int>(rand()) + total + 1; // genrate the rand number
for (u_int j = 0; j < i + 1; j++) {
if (balls[i] == balls[j] &&
i != j) { // if duplicate rand number forward and recreate rand
i--;
break;
} else if (j == i) { // if rand number is that uniqe.
return reinterpret_cast<jint>(env->NewIntArray(balls[i]));
}
}

}
delete[] balls;*/
return 0;
}

jstring
SC::baseApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(BASE_URL);
}

jstring
SC::mentorApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(BODY_POWER_API_SOURCE_REF);
}

jstring
SC::mentorPhotoApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(COACH_PHOTO_BASE_URL);
}

jstring
SC::mentorDataApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(COACH_DATA_BASE_URL);
}

jstring
SC::mentorDataFaildApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(COACH_DATA_BASE_URL_FAILD);
}

jstring
SC::suppPhotoApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(SUPP_PHOTO_BASE_URL);
}

jstring
SC::profileDataApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(PROFILE_SEND_BASE_URL);
}

jstring
SC::profilePhotoApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(PHOTO_PROFILE_SEND_BASE_URL);
}

jstring
SC::registerUserApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(REGISTER_USER_BASE_URL);
}

jstring
SC::privacyUserApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(EXIST_USER_BASE_URL);
}

jstring
SC::updateMentorApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(UPD_URL);
}

jstring
SC::suppProdApiUrl(JNIEnv *env, jobject jclazz) {
return env->NewStringUTF(SUPP_PROD_URL);
}


jobjectArray
SC::mapParamToStringArray(JNIEnv *env, jobject jclazz) {

char *message[PARAM_LENGTH]
= {const_cast<char *>("type"),
const_cast<char *>("action"),
const_cast<char *>("user"),
const_cast<char *>("pass"),
const_cast<char *>("group"),
const_cast<char *>("netid"),
const_cast<char *>("consumer"),
const_cast<char *>("timestam"),
const_cast<char *>("agent"),
const_cast<char *>("login"),
const_cast<char *>("profile")};

jobjectArray ret = env->NewObjectArray(PARAM_LENGTH,
env->FindClass("java/lang/String"),
env->NewStringUTF(""));

for (int ic_ = 0; ic_ < PARAM_LENGTH; ic_++) {
env->SetObjectArrayElement(
ret, ic_, env->NewStringUTF(message[ic_]));
}

return ret;
}

و برای استفاده هم در سمت اندورید هم به روش های زیر انجام دهید.

static {
System.loadLibrary("native-lib");
}

public
static native byte[] encrypt(byte[] bytes);

public
static native byte[] decrypt(byte[] bytes);

public
static native int customRand(int total,int totalDraw);

public
static native String baseApiUrl();

public
static native String mentorApiUrl();

public
static native String mentorPhotoApiUrl();

public
static native String suppPhotoApiUrl();

public
static native String mentorDataApiUrl();

public
static native String mentorDataFaildApiUrl();

public
static native String profileDataApiUrl();

public
static native String profilePhotoApiUrl();

public
static native String registerUserApiUrl();

public
static native String privacyUserApiUrl();

public
static native String updateMentorApiUrl();

public
static native String suppProdApiUrl();

public
static native String[] mapParamToStringArray();


public interface ApiPropertiesService {

@Native
String BASE_URL = baseApiUrl();

@Native
String BODY_API_URL = BASE_URL + mentorApiUrl();

@Native
String MENTOR_PHOTO_BASE_URL = BASE_URL + mentorPhotoApiUrl();

@Native
String SUPP_PHOTO_BASE_URL = BASE_URL + suppPhotoApiUrl();

@Native
String COACH_DATA_BASE_URL = BODY_API_URL + mentorDataApiUrl() ;

@Native
String COACH_DATA_BASE_URL_FAILD = BODY_API_URL + mentorDataFaildApiUrl() ;

@Native
String PROFILE_SEND_BASE_URL = BODY_API_URL + profileDataApiUrl() ;

@Native
String PHOTO_PROFILE_SEND_BASE_URL = BODY_API_URL + profilePhotoApiUrl();

@Native
String REGISTER_USER_BASE_URL = BODY_API_URL + registerUserApiUrl();

@Native
String EXIST_USER_BASE_URL = BODY_API_URL + privacyUserApiUrl();

@Native
String UPD_URL = BODY_API_URL + updateMentorApiUrl();

@Native
String SUPP_URL = BODY_API_URL + suppProdApiUrl();

@Native
String[] MAP_PARAM = mapParamToStringArray();
}
String pass = "abcd";
encryption(pass.toByte());

private String encryption(byte[] jByte) {

try {
if (jByte != null && jByte.length > 0) {
byte[] enc = encrypt(jByte);
StringBuilder byteToStr = new StringBuilder();
for (byte readByte : enc) {
byteToStr.append((char) readByte);
}

return byteToStr.toString();
}
} catch (Exception e) {
e.printStackTrace();
}

return "";
}

private String decryption(byte[] encryptedBytes) {

try {
if (encryptedBytes != null && encryptedBytes.length > 0) {
byte[] dec = decrypt(encryptedBytes);
StringBuilder byteToStr = new StringBuilder();
for (byte chars : dec) {
if (chars != 27)
byteToStr.append((char) chars);
}
Log.i("NativeTagLog", "dec with C++‎‎ : " + byteToStr.toString() + " and len dec data : " + byteToStr.length());
return byteToStr.toString();
}
} catch (Exception e) {
e.printStackTrace();
}

return "";
}