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)
Related
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.
For creating firebase custom auth tokens, I am using third party JWT library (https://github.com/jwtk/jjwt)
In this library, there is an option to add firebase Custom Token Claims like (alg, iss,sub,aud,iat etc.)
All firebase information is available at https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_a_third-party_jwt_library
private_key = "-----BEGIN PRIVATE KEY-----... -----END PRIVATE KEY-----";
I had passed private key in signWith method with encoding in base64
val encodeKey = Base64.encode(privateKey.toByteArray(), android.util.Base64.DEFAULT)
val jwt = Jwts.builder().setIssuer("firebase-adminsdk-kywht#...")
.setSubject("firebase-adminsdk-kywht#...")
.setAudience("https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit")
.setExpiration(calendar.time) //a java.util.Date
.setIssuedAt(Date())
.setId(UUID.randomUUID().toString())signWith(SignatureAlgorithm.RS512 ,encodeKey).compact()
I have used the above code but it did not work.
Anyone knows how to pass a private key to generate token?
first thing is whether you had missed a dot in your code acccidentally or not so put that and the parameters for signWith() is not correct i.e. first parameter is key and second one is signature algorithm. try this:
val encodeKey = Base64.encode(privateKey.toByteArray(), android.util.Base64.DEFAULT)
val jwt = Jwts.builder().setIssuer("firebase-adminsdk-kywht#...")
.setSubject("firebase-adminsdk-kywht#...")
.setAudience("https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit")
.setExpiration(calendar.time) //a java.util.Date
.setIssuedAt(Date())
.setId(UUID.randomUUID().toString())
.signWith(encodeKey, SignatureAlgorithm.RS512) //changed here
.compact()
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 :)
A lot of people ask how to write server side code
for in-app billing verificartion.
Can anybody publish such code? Or know where such code is.
How to install in on the server?
There are similar subjects
I could not understand it.
I don't know php.
Is it the next nightmare which I must study?
Thanks for help and advices.
Actually it's pretty easy, you just need a small function like this in PHP:
function checkPayment($data, $signature)
{
$base64EncodedPublicKey = "yourBase64PublicKey";
$openSslFriendlyKey = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($base64EncodedPublicKey, 64, "\n") . "-----END PUBLIC KEY-----";
$publicKeyId = openssl_get_publickey($openSslFriendlyKey);
$result = openssl_verify ($data, base64_decode($signature), $publicKeyId, OPENSSL_ALGO_SHA1);
/*
if ($result == 1) {
echo "Success";
} elseif ($result == 0) {
echo "Verification Failed";
}
*/
return $result;
}
Here is (uncompleted) python example:
from M2Crypto import BIO, RSA, EVP
ANDROID_PK = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgmZW0GxWr0v1ndLfxHbV2ruWcmQ
<some lines skipped>
cwWjx5sWSahVp0M5aYRysSkGGjSxe1wIDAQAB
-----END PUBLIC KEY-----"""
def validate_google_play_signature(signed_data, signature_base64, public_key):
# http://stackoverflow.com/a/546476/227024
bio = BIO.MemoryBuffer(public_key)
rsa = RSA.load_pub_key_bio(bio)
pubkey = EVP.PKey()
pubkey.assign_rsa(rsa)
pubkey.reset_context(md="sha1")
pubkey.verify_init()
pubkey.verify_update(signed_data)
signature = base64.b64decode(signature_base64)
return bool(pubkey.verify_final(signature))
I am having problems verifying a signature which I've just created. After signing I first convert the signature to text using Base64 and as a test I wanted to verify that I can decode the Base64 and verify the signature. This fails. Here is some code without the error handling.
I have my keypair:
DSAPrivateKey privateKey = (DSAPrivateKey) keyPair.getPrivate();
DSAPublicKey publicKey = (DSAPublicKey) keyPair.getPublic();
Now I sign some text and print to log output - it seems fine:
String text = "test";
Signature signer = null;
signer = Signature.getInstance(privateKey.getAlgorithm());
SignedObject signedObject = null;
signedObject = new SignedObject(text, privateKey, signer);
String print_signature = Base64.encodeToString(signedObject.getSignature(), Base64.DEFAULT);
System.out.println("Base64 Signature: " + print_signature);
Now I verify the signature using the SignedObject object created above and not the Base64. This is successful:
Signature verifier = null;
verifier = Signature.getInstance(publicKey.getAlgorithm());
boolean b = signedObject.verify(publicKey, verifier));
For my app I will only have the public certificate of the signer and the Base64 encoded string so I must verify the signature using these parameters only and can therefore AFAIK not use a SignedObject object. I used the Signature object:
Signature verifier1 = null;
verifier1 = Signature.getInstance(publicKey.getAlgorithm());
verifier1.initVerify(publicKey);
verifier1.update(text.getBytes()); // sorry I forgot this in original posting
byte[] sig1 = Base64.decode(print_signature, Base64.DEFAULT);
b = verifier1.verify(sig1));
This verification always fails (b = false).
Why are you using the SignedObject in the first place? What does it buy you? As for the verify failure, make sure that you get the same bytes after transmission/receiving. Are you sending/receiving in the same encoding? Is someone modifying the string?