I’m trying to sign an android .apk file on the server completely with php.
For this I need to generate the files contained in META-INF directory inside the .apk file(which is essentially a ZIP file). Creating the .MF and .SF files in php is fairly simple. However, I'm struggling with the .RSA file.
Unfortunately, I don’t know anything about cryptography and don’t even understand the basic terms. I only know some PHP basics, but I’m far from experienced and have no overview of the necessary libraries/functions. Therefore even after many hours of research, I still wasn’t able to create anything useful.
From what I understand, the .RSA file should contain:
digital signature of the .SF file
certificate with signers public key
This file should be PKCS7 formatted.
I was trying to use the phpseclib for this. I was able to create a private/public key/certificate from the examples on the internet, but I’m absolutely not able to put it all together to form the .RSA file.
Stackoverflow has been a great source of information and I probably found most of the answers to my questions here. However, now I’m stuck.
Could you guys please give me some php example code(ideally)? Or even some pseudocode/algorithm…
Is this even possible to accomplish with phpseclib/php? Will there be some “bit shifting” necessary?
If possible, please don’t point me to the source code of jarsigner…I looked at it, but don’t know much about java and it only brought more questions.
Update:
It’s hard to move in the right direction when you have no idea what you are actually doing :D…
This is what I tried so far, but without any success:
I generated public/private key pair with ssh
ssh-keygen -t rsa1
I used the previously generated keypair to create a self-signed certificate with phpsceclib as described here:
http://phpseclib.sourceforge.net/new/x509/tutorial.html#selfsigning
I passed the certificate ($signcert), private key ($privkey - from ssh generated file) and data for signing ($infilename –> the .SF file) to the openssl function openssl_pkcs7_sign():
openssl_pkcs7_sign ($infilename , $outfilename , $signcert , $privkey , array(), PKCS7_DETACHED|PKCS7_BINARY);
However, the generated result seems to be in something called PEM format (human readable). Besides the fact that it’s not in binary DER (don’t even know what that is…just guessing that it should be DER) which the final .RSA file should be, there are also some other issues with it:
the result also contains the content of the .SF file (the original data to be signed itself)
it contains some unnecessary header information as regular text string
lines end with “\n” and not with “\r\n”
the signature (not really sure what the other data in the result is, but probably the signature) is base64 encoded
Am I doing at least something right here? What other steps have to be taken to make it work? What properties should I set when creating the certificate according to the mentioned link? How could I transfer the result to binary DER-formatted .RSA file containing the .SF signature and certificate with signers public key?
Update 2:
I finally had some time to continue with my little experiment. I went through my code and tried to change different parameters. Finally I found the issue. It seems that I only needed to turn on the PKCS7_NOATTR flag in the openssl_pkc7_sign().
Here is the code
$configs = array('digest_alg' => 'sha1',
'x509_extensions' => 'v3_ca',
'req_extensions' => 'v3_req',
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
'encrypt_key' => true,
'encrypt_key_cipher' => OPENSSL_CIPHER_3DES);
// Generate private/public key pair and certificate
$privkey = openssl_pkey_new($configs);
$dn = array("commonName" => "name",
"emailAddress" => "me#example.com");
$csr = openssl_csr_new($dn, $privkey, $configs);
$sscert = openssl_csr_sign($csr, NULL, $privkey, 999, $configs);
// Sign the .SF file
openssl_pkcs7_sign ( $sfFile , $rsaFile , $sscert , $privkey, array(),
PKCS7_DETACHED|PKCS7_BINARY|PKCS7_NOATTR);
I only had time to check it on a couple of samples, but it seems to be working now. Here is a very simple demonstration www.balabeng.com/?q=appsigner
Related
so I'm working on an app that has existed for some years and I'm having some issues with Firebase. Some advice I've gotten is downloading a new google-services.json file from the console.
I've done that but this file is more different from my current file than I was expecting and I don't feel comfortable switching it out.
The biggest changes have happened to the oauth_client where for each client 1 oauth client has been removed. This oauth client always had: client_id, client_type and android_info which further contained a package_name and certificate_hash.
Now my remaining oauth clients only have a client_id and client_type.
Does anyone know why that client with more info got removed? Is this something that used to be present in the config file and has now been removed? Or could it be that maybe someone did something in the app along the line where this client was no longer necessary?
I'd like to understand the info in the config file, but if no one can explain it to me I'd settle for knowing if I can always trust the console to have an accurate config file or if I should keep the one we've been using?
So, basically I'm at step 1 of implementing App Links, I stumbled upon this tool:
https://developers.google.com/digital-asset-links/tools/generator
I give it my domain name, my package name, and I copy paste my App package fingerprint from the play store console. it generate an assetlinks.json file for me, I put it as required at https://my-domain/.well-known/assetlinks.json I test downloads, it works, then I ask this tool to test it, it says
No app deep linking permission found for package_name at my_domain.
my logs indicate that GoogleAssociationService came and took the file (200 status response and the correct number of bytes).
So basically I put the good values, it generates it, and then fetch it and tells me it's wrong, what am I missing ? how can he not be happy with what he generated itself ?
When we came across this issue we have also investigated logs of our proxy and have seen that the "assetlinks.json" file had been successfully downloaded.
In our case, the problem was with Content-Type. In our case, it was the "application/octet-stream" type. According to the documentation, Content-Type should have the type "application/json". We have changed the content type and everything started working as expected.
Check the requirements using the link above and verify that all of them are met by crossing off all potential reasons one by one.
Update 2022-10-30: The provided link is not available anymore. I have used a cached version to fetch the information below:
You must publish your JSON verification file at the following
location:
https://domain.name/.well-known/assetlinks.json
Be sure of the following:
The assetlinks.json file is served with content-type application/json.
The assetlinks.json file must be accessible over an HTTPS connection,
regardless of whether your app's intent filters declare HTTPS as the
data scheme.
The assetlinks.json file must be accessible without any
redirects (no 301 or 302 redirects).
If your app links support
multiple host domains, then you must publish the assetlinks.json file
on each domain. See Supporting app linking for multiple hosts.
Do not
publish your app with dev/test URLs in the manifest file that may not
be accessible to the public (such as any that are accessible only with
a VPN). A work-around in such cases is to configure build variants to
generate a different manifest file for dev builds.
can anyone help me with the following question please:
My Android-App is able to send the data via https when compiling the debug-version, but the release version fails there.
The https certificate is not self-signed and the whitelist plugin is working.
Interesting is, that if the debug version is installed and then the release version is installed without deinstalling the debug-version, everything works out well.
Can anyone help me here? Thank you in advance!
Problem solution:
The SSL-Chain was the problem for me.
1) To check if this might be an issue for your app, too, you may go to:
https://www.digicert.com/help/
Type in your domain (if already available online) and test your SSL-Configuration. If the last point does not say "SSL Certificate is correctly installed" and you bought your certificate from a trustworthy authority, this website already hints you at an issue you might have with the intermediate certificates.
2) Fix issue:
a) The intermediate certificates neccessary came with that SSL.rar-file you've once gotten. With the provider I had chosen, they sent me three .pem files (besides of other files of course) named:
01_COMODO_RSA_Organization_Validation_Secure_Server_CA, 02_COMODO_RSA_Certification_Authority,
03_AddTrust_External_CA_Root
Other authorities might send you something like someName.ca-bundle. That's the same thing, as far as I understood it, and so can skip this a) part.
Concatenate the plain text of these three files, meaning store them in another file - altogether. No additional text changes neccessary. When storing this file, make sure it has the .crt file ending.
b) Upload your chosenName.crt to your server into the same folder your ssl.crt is stored in already.
c) Make this new file known within the system. In your .config file (e.g. default-ssl.conf), the same file you once added the paths to your "ssl".crt and .key in, set "SSLCertificateChainFile" to - example path: "/etc/ssl/ssl.crt/chosenName.crt" - and update the certficates (I used the command update-ca-certificates, but I'm not sure if this was neccessary at all.)
d) Stop and start your webserver. If an error message regarding wrong configuration is displayed, you have probably misstyped the path to the file or it's name and so it cannot be found. If your webserver starts successfully, you're done.
Another check on the link above (I am not allowed to have more than 2 links within this post) should now show you the SSL-Chain (containing now 4 instead of 1 certificate_s) and the above mentioned "SSL successfully installed" message should appear.
Hopefully this will help you!
Further info:
Whether you need this SSL-Chain with 4 certificates or not is probably something that can vary. I looked it up on the comodo-support site because that was the SSL-certificate authority I had to deal with:
https://support.comodo.com/index.php?/Default/Knowledgebase/Article/View/620/0/which-is-root-which-is-intermediate
I am experiencing an infuriating bug with the Google Drive API for Android. Specifically, in presenting an "Open File from Google Drive" UI to the user, I am querying for the files in a folder using the following code:
String query = "'" + folderId + "' in parents and trashed = false";
Files.List request = service.files().list().setQ(query);
FileList files = request.execute();
java.util.List<File> items = files.getItems(); // Returns null!
When I run this code directly from Eclipse (i.e. signed with the debug certificate), there is no problem. However, when I build and run a signed APK using our release certificate, the call to files.getItems() returns null.
Oddly, while getItems() returns null, there is definitely data returned from the Drive server, because calling files.toString() shows a mess of Json, amongst which I have identified the filenames of a few of my files, so I don't think the problem is an authentication issue.
Also, using different folderIds in the query string does not seem to make any difference to the Json returned by toString(). Based on aggressive GC activity in logcat, it looks like the server might be returning ALL files in my drive, especially odd considering getItems() returns null.
Note that the code works absolutely fine when signed with the debug certificate, as I am able to browse my Google Drive perfectly from within my app.
As per earlier comment:
Any chance Proguard kicks in when exporting your signed APK? If you rely on i.e. variable names to map the JSON onto POJOs, this is likely to brake without the appropriate Proguard exclusions/rules. Have a look in your project.properties file and comment out any lines in the form of proguard.config=<file_name>. After that, export another signed APK and retest.
We have an app that stores some data localy, none of this data is valuable to anyone else except the user and us. So, we don't need to encrypt it, but we do want to make sure that nobody has changed it.
I figured the easiest way to do this is to generate a hash from file contents, date stamp and/or size. Doing straight md5 is probably not good enough, because who ever wants to change the data could just generate a new hash, so it would be nice to use some sort of the key. Does anybody know of a simple way to do this? I would like to avoid using libraries such as crypto++, but not 100% against it.
Oh, and we are doing the app in C++.
Maybe, I just need to add some obscure data to whatever we pass to the md5 function and be done with this. What do you guys think?
Just to reiterate, file has no valuable info to hackers, so there is no reason to go overboard with security. I just want to check if the settings have been messed with.
Thanks,
Angrius.
PS> does anyone know a good way to implement md5 that would work on both?
If you want to sign the data, you will need to use a key and a signature algorithm. Either an asymmetric one like RSA or a symmetric one such as AES. However, if your app needs to sign data with it, the key needs to be embedded or otherwise made available to the app. In that case a potential attacker can extract it from the app and create their own, valid signatures. You decide if that is OK with you and how far you want to go in protecting it.
Adding 'obscure data' or otherwise trying to come up with your own algorithm is a bad idea, you are bound to get it wrong, especially if you don't have experience in this field. Do use a standard algorithm, and think how you will protect keys (use iOS key chain, etc.). Search for "RSA sigantures" or "HMAC" to get more details about how to do this in practice. If you cannot take advantage of the platform's cryptographic APIs from your C++ library(?), you will need to use and link to a third-party library such as OpenSSL.
The simplest way to do what i wanted to do is to implement basic HMAC (http://en.wikipedia.org/wiki/Hash-based_message_authentication_code). You can even store this hash inside the config file itself, although that's a bit more complicated, but pretty neat.
Turns out that both iOS and Android have built in libraries to do basic SHA1, MD5 and so on. They also both support HMAC. So for iOS you would do something like this:
#include <CommonCrypto/CommonHMAC.h>
string createHMAC( string key, string text )
{
string result;
const char *cKey = key.c_str();
const char *cData = text.c_str();
unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
CCHmac( kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC );
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
{
[output appendFormat:#"%02x", cHMAC[i]];
}
result = string( [output UTF8String] );
return result;
}
Since this is objective-c code, you can compile this as objective-c++ and it will work. If your app doesn't require any advanced cryptography, there is no need to use any frameworks.
Cheers,
Angrius