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)
Related
I already know to get the public key from base58 encoded private key using an ECKey object in BitcoinJ. See the example code.
String base58PrivateKeyString = "---------------------private key here---------------------";
NetworkParameters params = MainNetParams.get();
ECKey key;
if (base58PrivateKeyString.length() == 51 || base58PrivateKeyString.length() == 52) {
DumpedPrivateKey dumpedPrivateKey = DumpedPrivateKey.fromBase58(params, base58PrivateKeyString);
key = dumpedPrivateKey.getKey();
} else {
BigInteger privKey = Base58.decodeToBigInteger(base58PrivateKeyString);
key = ECKey.fromPrivate(privKey);
}
// I'm not sure that I'm correct. Is this the correct compressed public key?
String publicKey = Hex.toHexString(ECKey.publicKeyFromPrivate(Base58.decodeToBigInteger(base58PrivateKeyString), true));
String bitcoin address; // I don't know how to get
But I still don't understand to take the compressed private key and the bitcoin address from the "key" object. I tried some with compressPoint() method. But I didn't succeed.
In order to get the compressed public key for a qualified WIF just use the following function in the bitcoinJ library.
String publicKey = key.getPublicKeyAsHex();
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;
}
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()))
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);
}