/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.olm;
import android.text.TextUtils;
import android.util.Log;
import java.util.Random;
/**
* Olm SDK helper class.
*/
public class OlmUtility {
private static final String LOG_TAG = "OlmUtility";
public static final int RANDOM_KEY_SIZE = 32;
public static final int RANDOM_RANGE = 256;
private transient int mUnreleasedCount;
/** Instance Id returned by JNI.
* This value uniquely identifies this utility instance.
**/
private long mNativeId;
public OlmUtility() {
initUtility();
}
/**
* Create a native utility instance.
* To be called before any other API call.
* @return true if init succeed, false otherwise.
*/
private boolean initUtility() {
boolean retCode = false;
if(0 != (mNativeId = initUtilityJni())){
mUnreleasedCount++;
retCode = true;
}
return retCode;
}
private native long initUtilityJni();
/**
* Release native instance.
* Public API for {@link #releaseUtilityJni()}.
*/
public void releaseUtility(){
releaseUtilityJni();
mUnreleasedCount--;
mNativeId = 0;
}
private native void releaseUtilityJni();
/**
* Verify an ed25519 signature.
* If the signature is verified, the method returns true. If false is returned, an error description is provided in aError.
* If the key was too small, aError is set to "OLM.INVALID_BASE64".
* If the signature was invalid, aError is set to "OLM.BAD_MESSAGE_MAC".
* @param aSignature the base64-encoded message signature to be checked.
* @param aFingerprintKey the ed25519 key (fingerprint key)
* @param aMessage the signed message
* @param aError error message description
* @return true if the signature is verified, false otherwise
*/
public boolean verifyEd25519Signature(String aSignature, String aFingerprintKey, String aMessage, StringBuffer aError) {
boolean retCode = false;
String jniError;
if (null == aError) {
Log.e(LOG_TAG, "## verifyEd25519Signature(): invalid input error parameter");
} else {
aError.setLength(0);
if (TextUtils.isEmpty(aSignature) || TextUtils.isEmpty(aFingerprintKey) || TextUtils.isEmpty(aMessage)) {
Log.e(LOG_TAG, "## verifyEd25519Signature(): invalid input parameters");
aError.append("JAVA sanity check failure - invalid input parameters");
} else if (null == (jniError = verifyEd25519SignatureJni(aSignature, aFingerprintKey, aMessage))) {
retCode = true;
} else {
aError.append(jniError);
}
}
return retCode;
}
/**
* Verify an ed25519 signature.
* Return a human readable error message in case of verification failure.
* @param aSignature the base64-encoded message signature to be checked.
* @param aFingerprintKey the ed25519 key
* @param aMessage the signed message
* @return null if validation succeed, the error message string if operation failed
*/
private native String verifyEd25519SignatureJni(String aSignature, String aFingerprintKey, String aMessage);
/**
* Compute the hash(SHA-256) value of the string given in parameter(aMessageToHash).
* The hash value is the returned by the method.
* @param aMessageToHash message to be hashed
* @return hash value if operation succeed, null otherwise
*/
public String sha256(String aMessageToHash) {
String hashRetValue = null;
if(null != aMessageToHash){
hashRetValue = sha256Jni(aMessageToHash);
}
return hashRetValue;
}
private native String sha256Jni(String aMessage);
/**
* Helper method to compute a string based on random integers.
* @return string containing randoms integer values
*/
public static String getRandomKey() {
String keyRetValue;
Random rand = new Random();
StringBuilder strBuilder = new StringBuilder();
for(int i = 0; i< RANDOM_KEY_SIZE; i++) {
strBuilder.append(rand.nextInt(RANDOM_RANGE));
}
keyRetValue = strBuilder.toString();
return keyRetValue;
}
/**
* Return the number of unreleased OlmUtility instances.
* @return number of unreleased instances
*/
public int getUnreleasedCount() {
return mUnreleasedCount;
}
}