I have this code on Android:
val digest = MessageDigest.getInstance("SHA-512")
digest.update("secretotpkey".toByteArray())
val sb = StringBuilder()
val bytes = digest.digest(value.toByteArray())
bytes.forEach {
sb.append(((it and 0xF) + 0x100).toString(16).substring(1))
}
val encryptedValue = sb.toString()
makeLog("Encrypted value is $encryptedValue")
return encryptedValue
I am trying to convert this to iOS by using CryptoSwift. However I am getting different results. Any ideas how to fix?
var digest = Digest.sha512("secretotpkey".bytes)
print(digest)
let bytes = "54181474".bytes
print(bytes)
digest.append(contentsOf: bytes)
var blah = String()
for item in digest {
let a = Int(item & 0xF) + Int(0x100)
let b = (String(format:"%02X", a)).substring(range: NSRange(location: 1, length: 2))
print(b)
blah.append(b)
}
Two encoding issues:
you're not indicating the characters set when converting the key to bytes (a key should consist of bytes in the first place, strings are not keys).
your hex encoding is clearly not correct for either Kotlin or Swift; please use a pre-made library call instead or look up correct code here on StackOverflow.
That should fix it, because there is nothing there but a call to a standardized algorithm, SHA-512 otherwise.
Related
What I have is private key without header, footer and spaces (it's test one)
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg0m4yLz+sdzZtBG9Q3HQ9++wcfq1O4hOWgSBMb/A6eijyhRANCAAQeB0fBl2D7HZOKVBjpPiU2jabzNxQU4ZYrJ+MSA3LpzZxmRk2JaFHNujjkJghQT19HHjg3Fnkb8Y9oIhB9neXBI
And this code in android which generates signature in required format.
val signatureSHA256 = Signature.getInstance("SHA256withECDSA")
val encoded = Base64.decode(privateKeyHere, Base64.DEFAULT)
val privateKey: PrivateKey = KeyFactory.getInstance("EC").generatePrivate(PKCS8EncodedKeySpec(encoded))
signatureSHA256.initSign(privateKey)
val finalSignature = signatureSHA256.sign().toHexString()
//Somewhere
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
And function which return timestamp:
fun getXTimestamp(): Long {
return (System.currentTimeMillis() / 1000L)
}
From android Im getting finalSignature and getXTimestamp()
And I need to verify my signature in php script:
$timestamp = '1625730735';
$public_key = "
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHgdHwZdg+x2TilQY6T4lNo2m8zcU
FGWKyfjEgNy6c2cZkZNiWhRzbo45CYIUE9fRx44NxZ5G/GPaCIQfZ3lwSA==
-----END PUBLIC KEY-----
";
//hex2bin("finalSignature")
$sign = hex2bin("3045022048011d511094a5270c528ca5064b07084e36ccfd2ee3f5e1e20278fb5d83cdba022100d71a0096ef2c6288554a51017a89374b18c7e84ba7031a43d67f53d7ce89152c");
$result = openssl_verify($timestamp, $sign, $public_key, OPENSSL_ALGO_SHA256);
print $result;
Now php script launched from console returns 0 but should return 1.
I think I should somehow update or put timestamp in signature.
I tried to put it in update() as bytes, but still got 0
Who can help pls?)
On PHP side ("verification") you use your 'timestamp' as text string as input for your openssl_verify function.
On Kotlin-side you need to do the same - get the timestamp as string and use it as input for a sign.update call with [Pseudo-code] timestamp-string.getBytes(StandardCharset.UTF8) as input.
As I'm not familiar with Kotlin I'm using the code in the comment of #Andrej Kijonok as it solves the problem :-)
val signatureTimestamp = getXTimestamp().toString().toByteArray(Charsets.UTF_8)
signatureSHA256.initSign(privateKey)
signatureSHA256.update(signatureTimestamp)
I wanna upload some files which are 30 MB Max to my server with okhttp websocket.
The websocket transfer allows String or ByteString only.
So I want to convert my file to ByteString and then upload this to my server via websocket(Nodejs).
I use ByteString.of() to convert this byteArray like this.
val file = "../tmp/file.jpg"
try {
val encoded:ByteArray = Files.readAllBytes(Paths.get(file))
val byteString = ByteString.of(encoded,0,1024)
..send data
Log.d("log1","DATA DONE")
} catch (e: IOException) {
Log.d("log1","ERROR:"+e)
}
But what confuses me is that ByteString function takes 3 parameters..
First: ByteArray
Second: Offset
Third: Bytecount
My question is what does the last 2 parameters do and the reason behind it? I don't find any clear documentation about this. Just the roadmap that its added.
If you have any links or suggestions please let me know.
-Offset is actually where you want to start reading your bytes from.
Assume a Text file with the following data
Computer-science World
Quantum Computing
now the offset for the first line is 0 <0,Computer Science World> for the second line the offset will be <23,Quantum Computing>
-ByteCount is the number of bytes you want to count(include)
Let's help you with a piece of simple code
byte[] bytes1 = "Hello, World!".getBytes(Charsets.UTF_8);
ByteString byteString = ByteString.of(bytes1, 2, 9);
// Verify that the bytes were copied out.
Sytem.out.print(byteString.utf8());
Answer is : llo, Worl
So basically, method can be used as a substring. But since you want to send in all the bytes, you can simply use
fun of(vararg data: Byte): ByteString
I'm trying to run a call to Marvel Api however the return I'm having is code = 401 Unauthorized, this is due to not being able to send the timeStamp and hash parameters correctly.
the url base is http://gateway.marvel.com/v1/public/ -> my url is being: = http: //gateway.marvel.com/ v1 / public / characters? name = wolverine & apikey = XXX & ts = 2019-04-06% 2013: 09: 10.272 & hash = [B # afad7ce8]
In the documentation it is described that I need to send these parameters:
Params: {
"apikey": "your api key",
"ts": "a timestamp",
"hash": "your hash"
}
I need help to generate the ts and hash correctly.
Note: hash = ts + apiKey + publicKey
var ts = Timestamp(System.currentTimeMillis())
var hash = getHash(ts.toString())
fun getHash(ts: String): ByteArray? {
val byte = ts.toByteArray() + API_KEY.toByteArray() + PUBLIC_KEY.toByteArray()
val md = MessageDigest.getInstance("MD5")
return md.digest(byte)
}
You should not put your private key in code (it's bad practice and usually with this key you can do CRUD operations with API and even drop some parts of database).
Get your Marvel public key (for example 1234), your private key(for example abcd) and choose timestamp (for example 1564731162583).
Go to website https://passwordsgenerator.net/md5-hash-generator/
put your strings like 1564731162583abcd1234 (timestamp + private key + api key without spaces). You will get (with parameters from example) hash: B5936DEBCC1A252C679D2D3E5361B6C0
One more important thing: when you add this hash in your api call, timestamp have to be the same as in hash (previously chosen example 1564731162583) and also MD5 hash have to be in lowercase. This is important.
Hope it will help :)
I need an end to encrypt different strings and related decryptions after user authenticate using fingerprint scanner.
Following this project (https://github.com/StylingAndroid/UserIdentity/tree/Part1) and changed "tryEncrypt" method like below:
private boolean tryEncrypt(Cipher cipher) {
try {
cipher.doFinal(SECRET_BYTES);
String one = "augusto";
String two = "test#gmail.com";
String three = "3333333331";
byte[] oneEnc = cipher.doFinal(one.getBytes());
byte[] twoEnc = cipher.doFinal(one.getBytes());
byte[] threeEnc = cipher.doFinal(one.getBytes());
Log.d("test", "oneEnc: " + Base64.encodeToString(oneEnc,0));
Log.d("test", "twoEnc: " + Base64.encodeToString(twoEnc,0));
Log.d("test", "threeEnc: " + Base64.encodeToString(threeEnc,0));
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
I'm getting this error:
java.lang.IllegalStateException: IV has already been used. Reusing IV in encryption mode violates security best practices.
What is the correct way on how to do it?
Thanks
*******************UPDATE:*****************************
To help others to get solve this problem I used this library and worked like charm:
https://github.com/Mauin/RxFingerprint
You have a problem because your are using a single instance of the Cipher for multiple encryptions (dofinal). You are using a single vector initialization (IV).
Take a look on an option of how to initialize a cipher.
SecureRandom r = new SecureRandom();
byte[] ivBytes = new byte[16];
r.nextBytes(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(ivBytes));
As you can see, you need to specify the initialization vector. The initialization vector can not be repeated to guarantee that the encryption works.
In your scenario, you probably gonna need to perform a new initialization.
*Ps: It's also possible to use the Cipher initialization without the IvParameterSpec. In this scenario, the class will generate one for you. However, I believe that you need to perform a initialization per DoFinal to guarantee some randomness.
To help others to get solve this problem I used this library that worked like charm:
https://github.com/Mauin/RxFingerprint
I want to append a line of text to an existing Azure cloud block blob from an Android device.
In VB.Net I would AcquireLease, getBlockBlobReference, DownloadToFile, add the line on the local files system, UploadToFile, ReleaseLease . Simple and secure, if a bit long-winded.
In Android, it looks a little more tricky. At the moment, my best solution is this:
CloudBlockBlob blob1=container.getBlockBlobReference(chosenOne+".txt");
String proposedLeaseId1 = UUID.randomUUID().toString();
OperationContext operationContext1 = new OperationContext();
blob1.acquireLease(15, proposedLeaseId1, null /*access condition*/,null/* BlobRequestOptions */, operationContext1);
AccessCondition condition = new AccessCondition();
condition.setLeaseID(proposedLeaseId1);
BlobInputStream blobIn = blob1.openInputStream();
blob1.downloadAttributes();
long blobLengthToUse = blob1.getProperties().getLength();
byte[] result = new byte[(int) blobLengthToUse];
blob1.downloadToByteArray(result,0);
blobIn.close();
CloudBlockBlob blob1 = container.getBlockBlobReference(chosenOne+".txt");
String proposedLeaseId1 = UUID.randomUUID().toString();
OperationContext operationContext1 = new OperationContext();
blob1.acquireLease(15, proposedLeaseId1, null /*access condition*/,null/* BlobRequestOptions */, operationContext1);
AccessCondition condition = new AccessCondition();
condition.setLeaseID(proposedLeaseId1);
BlobInputStream blobIn = blob1.openInputStream();
blob1.downloadAttributes();
long blobLengthToUse = blob1.getProperties().getLength();
byte[] result = new byte[(int) blobLengthToUse];
blob1.downloadToByteArray(result,0);
blobIn.close();
blob1.deleteIfExists(DeleteSnapshotsOption.NONE,condition, null, operationContext1);
BlobOutputStream blobOut = blob1.openOutputStream();
//this is a byte by byte write ...
//which is fine ... but no use if you want to replace ...
/*int next = blobIn.read();
while (next != -1) {
blobOut.write(next);
next = blobIn.read();
}*/
blobOut.write(result);
String strTemp="This is just a test string";
blobOut.write(strTemp.getBytes());
blobOut.close();
Apart from being extremely long-winded, I am concerned that as soon as I delete the blob, the lease will go and that I may hit integrity issues. I would appreciate any help in making this code simpler and more secure. I know that Microsoft are planning to introduce append blobs in 3Q 2015, but I want to implement this now.
You can call PutBlock to upload the appended content (the maximum size of each block is 4MB, so please split the appended content into blocks if required), and then call PutBlockList on this blob by passing in the previously committed blocks plus and newly appended blocks.