Currently our team is working on an HMAC key but the results on iOS and Android are different. The Java part is working fine but the iOS part appears not to be working.
We have established that the problem is with the HMAC_KEY in java the key first gets converted to a base16 byte[]. What would be the Objective-C equivelent to the following?
byte[] hmacKey = BaseEncoding.base16().decode(HMAC_KEY);
SecretKeySpec signingKey = new SecretKeySpec(hmacKey, HMAC_SHA256_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes(C_UTF8));
return BaseEncoding.base64().encode(rawHmac);
curently in ios we have the following:
NSData *saltData = [salt dataUsingEncoding:NSUTF8StringEncoding];
NSData *paramData = [signingData dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData* hash = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH ];
CCHmac(kCCHmacAlgSHA256, saltData.bytes, saltData.length, paramData.bytes, paramData.length, hash.mutableBytes);
NSString *base64Hash = [hash base64Encoding];
the problem is withing the BaseEncoding.base16().decode(HMAC_KEY) part how do we do this in Objective-C?
From your Java code, you need to convert HMAC_KEY(HexDecimalString) to NSData first, then you can do HMAC_SHA256 Calculation. This is my Swift solution
public extension String {
func sha256(key: NSData) -> String {
let inputData: NSData = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let keyData = UnsafePointer<UInt8>(key.bytes)
let algorithm = HMACAlgorithm.SHA256
let digestLen = algorithm.digestLength()
let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)
CCHmac(algorithm.toCCHmacAlgorithm(), keyData, key.length, inputData.bytes, Int(inputData.length), result)
let data = NSData(bytes: result, length: digestLen)
result.destroy()
return data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
}
func dataFromHexadecimalString() -> NSData? {
let data = NSMutableData(capacity: characters.count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .CaseInsensitive)
regex.enumerateMatchesInString(self, options: [], range: NSMakeRange(0, characters.count)) { match, flags, stop in
let byteString = (self as NSString).substringWithRange(match!.range)
var num = UInt8(byteString, radix: 16)
data?.appendBytes(&num, length: 1)
}
return data
}
}
enum HMACAlgorithm {
case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
func toCCHmacAlgorithm() -> CCHmacAlgorithm {
var result: Int = 0
switch self {
case .MD5:
result = kCCHmacAlgMD5
case .SHA1:
result = kCCHmacAlgSHA1
case .SHA224:
result = kCCHmacAlgSHA224
case .SHA256:
result = kCCHmacAlgSHA256
case .SHA384:
result = kCCHmacAlgSHA384
case .SHA512:
result = kCCHmacAlgSHA512
}
return CCHmacAlgorithm(result)
}
func digestLength() -> Int {
var result: CInt = 0
switch self {
case .MD5:
result = CC_MD5_DIGEST_LENGTH
case .SHA1:
result = CC_SHA1_DIGEST_LENGTH
case .SHA224:
result = CC_SHA224_DIGEST_LENGTH
case .SHA256:
result = CC_SHA256_DIGEST_LENGTH
case .SHA384:
result = CC_SHA384_DIGEST_LENGTH
case .SHA512:
result = CC_SHA512_DIGEST_LENGTH
}
return Int(result)
}
}
You can simply get base64Hash like this and the result was verified:
print(dataString.sha256(HMAC_KEY.dataFromHexadecimalString()))
Related
I've created a method in JAVA in order to do the same thing of an existing PHP function, that is: convert an arbitrarily large number from any base to any base.
The java method is working fine and I can convert numbers from one base to another and then convert it back, but the resulted strings are different from the PHP function. This is a problem to me, because I want to convert a number in PHP and then convert it back in JAVA.
For example, lets convert the number 998765;43210;9999;2 from Base11 with alphabet 0123456789; to Base21 with alphabet 0123456789ABCDEFGHIJK in PHP and JAVA:
Result of the example in PHP:
convBase("998765;43210;9999;2", "0123456789;", "0123456789ABCDEFGHIJK") = "GJK7K6B2KKGKK96"
Result of the example in JAVA:
convBase("998765;43210;9999;2", "0123456789;", "0123456789ABCDEFGHIJK") = "1B0EJAJ0IG3DABI"
I would like the results to be the same, so I could convert a number in PHP and convert it back in JAVA.
I think that the problem can be character encoding, but I don't know how to solve it.
PHP function and test:
<?php
function convBase($numberInput, $fromBaseInput, $toBaseInput)
{
if ($fromBaseInput==$toBaseInput) return $numberInput;
$fromBase = str_split($fromBaseInput,1);
$toBase = str_split($toBaseInput,1);
$number = str_split($numberInput,1);
$fromLen=strlen($fromBaseInput);
$toLen=strlen($toBaseInput);
$numberLen=strlen($numberInput);
$retval='';
if ($toBaseInput == '0123456789')
{
$retval=0;
for ($i = 1;$i <= $numberLen; $i++)
$retval = bcadd($retval, bcmul(array_search($number[$i-1], $fromBase),bcpow($fromLen,$numberLen-$i)));
return $retval;
}
if ($fromBaseInput != '0123456789')
$base10=convBase($numberInput, $fromBaseInput, '0123456789');
else
$base10 = $numberInput;
if ($base10<strlen($toBaseInput))
return $toBase[$base10];
while($base10 != '0')
{
$retval = $toBase[bcmod($base10,$toLen)].$retval;
$base10 = bcdiv($base10,$toLen,0);
}
return $retval;
}
header('Content-Type: text/html; charset=utf-8');
$number = "998765;43210;9999;2";
$fromBase = "0123456789;";
$toBase = "0123456789ABCDEFGHIJK";
$converted = convBase($number, $fromBase, $toBase);
$back = convBase($converted, $toBase, $fromBase);
echo "Number: ".$number."<br>";
echo "Converted: ".$converted."<br>";
echo "Back: ".$back."<br>";
?>
JAVA method and test:
import java.math.BigInteger;
public class ConvBase{
public static String convBase(String number, String fromBaseInput, String toBaseInput){
if (fromBaseInput.equals(toBaseInput))
return number;
BigInteger fromLen = new BigInteger(""+fromBaseInput.length());
BigInteger toLen = new BigInteger(""+toBaseInput.length());
BigInteger numberLen = new BigInteger(""+number.length());
if(toBaseInput.equals("0123456789")){
BigInteger retval = BigInteger.ZERO;
for(int i=1; i<=number.length(); i++){
retval = retval.add(
new BigInteger(""+fromBaseInput.indexOf(number.charAt(i-1))).multiply(
fromLen.pow(numberLen.subtract(new BigInteger(""+i)).intValue())
//pow(fromLen, numberLen.subtract(new BigInteger(""+i)))
)
);
}
return ""+retval;
}
String base10 = fromBaseInput.equals("0123456789") ? number : convBase(number, fromBaseInput, "0123456789");
if(new BigInteger(base10).compareTo(toLen) < 0)
return ""+toBaseInput.charAt(Integer.parseInt(base10));
String retVal = "";
BigInteger base10bigInt = new BigInteger(base10);
while(!base10bigInt.equals(BigInteger.ZERO)){
retVal = toBaseInput.charAt(base10bigInt.mod(toLen).intValue()) + retVal;
base10bigInt = base10bigInt.divide(toLen);
}
return ""+retVal;
}
public static void main(String[] args) {
String number = "98765;43210;9999;2";
String fromBase = "0123456789;";
String toBase = "0123456789ABCDEFGHIJK";
String converted = ConvBase.convBase(number, fromBase, toBase);
String back = ConvBase.convBase(converted, toBase, fromBase);
System.out.println("Number = "+number);
System.out.println("Converted = "+converted);
System.out.println("Back = "+back);
System.exit(0);
}
}
There is a typo in your test case. Both programs seem to be correct, or at least consistent.
Your Java variant converts "98765;43210;9999;2" while your PHP program converts "998765;43210;9999;2". Note the two nines at the beginning. When I changed the number I got the following output:
Number = 998765;43210;9999;2
Converted = GJK7K6B2KKGKK96
Back = 998765;43210;9999;2
which is consistent with the output of the PHP version.
I need help with making a signature in swift 3 with HMAC SHA1 for a web request.
I have an example in Java but really do not know how to do it in swift.
Java formula:
signature = Base64.encode(HMAC_SHA1.digest(data,Base64.decode(client_secret))
signature = +t2GOKtZt1hU+C7OGBKZbDOKxds=
swift 3 :
first convert the image into data.Then convert this imageData to base64 string.
imgData = UIImageJPEGRepresentation(image, 0.9)! as Data
strBase64 = imgData.base64EncodedString(options: .lineLength64Characters) as NSString
then use this base64 string wherever you want.
Solution:
extension Data {
func hmacsha1(key: String) -> String? {
guard let keyData = Data(base64Encoded: key, options: .ignoreUnknownCharacters) else {
return nil
}
var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
self.withUnsafeBytes({ dataBytes in
keyData.withUnsafeBytes({ keyDataBytes in
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), keyDataBytes, keyData.count, dataBytes, self.count, &digest)
})
})
return Data(bytes: digest).base64EncodedString()
}
}
Test:
let data = Data("Test".utf8)
let key = Data("Key".utf8).base64EncodedString()
let hmac = data.hmacsha1(key: key)
Result: "xIcCRlnXa+IqFtO+9AF3OqeRdAU="
Problem solved
extension String {
func hmac(algorithm: kCCHmacAlgSHA1, key: NSData) -> String {
let cKey = key
let cData = self.cString(using: String.Encoding.ascii)
var cHMAC = [CC_SHA1_DIGEST_LENGTH]
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), cKey.bytes, cKey.length, cData, Int(strlen(cData!)), &cHMAC)
let hmacData:NSData = NSData(bytes: cHMAC, length: cHMAC)
let hmacBase64 = hmacData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
return String(hmacBase64)
}
}
let hmacResult: String = cData.hmac(algorithm: HMACAlgorithm.SHA1, key: keyData)
I am trying to Loop BasicNameValuePair using Java.
I already have one working example in PHP.
Here is what I have:
ArrayList<NameValuePair> data = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("email", username));
postParameters.add(new BasicNameValuePair("pass", password));
public String sign_creator(ArrayList data){
String sig = "";
for(String key : data ){
String value = data[key];
sig += "" + key + "=" + value + "";
}
sig += "62f8ce9f74b12f84c123cc23437a4a32";
sig = md5(sig);
return data['sig'] = sig;
}
I am trying to implement this PHP logic in Java
$data = array(
"email" => #$_GET['u'],
"password" => #$_GET['p'],
);
function sign_creator(&$data){
$sig = "";
foreach($data as $key => $value){
$sig .= "$key=$value";
}
$sig .= "62f8ce9f74b12f84c123cc23437a4a32";
$sig = md5($sig);
return $data['sig'] = $sig;
}
A few things supported by PHP work differently in Java.
In Java, values are never passed by reference, only by value.
Associative arrays like those in PHP don't exist, in Java they're using HashMaps. However, a List with NameValuePairs is also possible.
String literals like 'sig' must be written in double quotes.
Variables can't be used inside string literals, so "$key=$value" won't work.
You are almost there, you just need to change a few things in the code:
// I guess you're using org.apache.commons.httpclient.NameValuePair
void addSign(List<NameValuePair> data) {
String sig = "";
for (NameValuePair pair : data) {
sig += pair.getName() + "=" + pair.getValue();
}
sig += "62f8ce9f74b12f84c123cc23437a4a32";
sig = md5(sig); // I assume you have an md5 method somewhere.
// You need to add the sig to the list
data.add(new BasicNameValuePair("sig", sig));
}
Note: You shouldn't use MD5, as it's being considered insecure. See this article.
You can use a Map for this purpose. I assume you are trying to create signature for a single user using username and password. So, you can return the signature from the sign_creator method . Here is the sample -
public static void main(String[] args) {
Map<String,String> data = new LinkedHashMap<String,String>();
data.put("email", "abcd");
data.put("password", "asadsabcd");;
System.out.println(sign_creator(data));
}
public static String sign_creator(Map<String ,String> data){
String sig = "";
for(Map.Entry<String, String> keyValPair : data.entrySet() ){
String value = keyValPair.getValue();
sig += "" + keyValPair.getKey() + "=" + value + "";
}
sig += "62f8ce9f74b12f84c123cc23437a4a32";
sig = md5(sig);
return sig;
}
I'm making an iOS app that parses JSON data from a google spreadsheet. One of the issues with Google JSON data is that it includes unnecessary data that has to be removed. I'm new to iOS programming.
/*O_o*/google.visualization.Query.setResponse({"version":"0.6","reqId":"0","status":"ok","sig":"1400846503","table":{JSON DATA I NEED}});
I have done this in JAVA on Android using this code
int start = result.indexOf("{", result.indexOf("{") + 1);
int end = result.lastIndexOf("}");
String jsonResponse = result.substring(start, end);
My swift code
var something = "My google JSON Data"
let Start = String(something).characters.indexOf("{")!;
let substring1: String = something.substringFromIndex(Start);
something = substring1;
let End = String(something).characters.indexOf(")")!.distanceTo(something.endIndex);
let index3 = something.endIndex.advancedBy(-End);
let substring4: String = something.substringToIndex(index3)
What I'm asking is how do I get the index of the 2nd "{"
You should use NSJsonSerializer, but if you want to do it your way:
extension String {
func indexOf(target: String) -> Int {
if let range = self.rangeOfString(target) {
return self.startIndex.distanceTo(range.startIndex)
} else {
return -1
}
}
func indexOf(target: String, startIndex: Int) -> Int {
let startRange = self.startIndex.advancedBy(startIndex)
if let range = self.rangeOfString(target, options: .LiteralSearch, range: startRange..<self.endIndex) {
return self.startIndex.distanceTo(range.startIndex)
} else {
return -1
}
}
}
let end = myString.indexOf("{", startIndex: myString.indexOf("{") + 1)
I am using this http://raginggoblin.wordpress.com/2012/08/11/java-alternative-to-php-crypt-function/ for the equivalent of php crypt function or does it says here that it is...
But I have the same value in java and in php but the hashing result is different.. I was wondering if not hashing is different because its not executed the same way ? I post this two values to a WS.
JAVA:
String doc_data="{\"table\":\"1048582\"}";
String data="$5$rounds=5000$503$La071hYxZERff9GGq0cb.x2k96Xx25\/C4vxQztQ7B96";
String result=Crypt.crypt(doc_data, data);
PHP:
$params['result'] = crypt($params['doc_data'], #$this->initdata['data']);
I logged it and I put the exact data in from POST... but the result is not the same.. There is no way to do this right ? or there is no equivalent?
Before that library I used Guava..but still not the same
public static String crypt_sha256(String password, String salt) {
int iteration_count = 5000;
HashFunction func = Hashing.sha256();
HashCode result = func.hashString(salt + param1, Charsets.UTF_8);
for (int i = 0; i < iteration_count; i++) {
result = func.hashBytes(result.asBytes());
}
return salt + result.toString();
}
Oke, so far I tested a few library's and the Winner is Apache's Crypt.
http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/Crypt.html
public static String crpyt_sha256_apache(String param1, String salt) {
return Crypt.crypt(param1, salt);
}