package com.fairphone.updater;
import android.content.Context;
import android.util.Base64;
import android.util.Log;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class RSAUtils {
private static final String TAG = RSAUtils.class
.getSimpleName();
public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
public static PublicKey readPublicKeyFormCertificate(Context context, int certificateResourceId) throws IOException, CertificateException{
InputStream in = context.getResources().openRawResource(certificateResourceId);
byte[] buff = new byte[4000];
int bytesRead;
ByteArrayOutputStream out = new ByteArrayOutputStream();
while((bytesRead = in.read(buff)) != -1) {
out.write(buff, 0, bytesRead);
Log.i(TAG, "bytes read: " + bytesRead);
}
byte[] publicKeyBytes = out.toByteArray();
CertificateFactory cf = CertificateFactory.getInstance("X509");
Certificate cert = cf.generateCertificate(new ByteArrayInputStream(publicKeyBytes));
PublicKey pubKey = cert.getPublicKey();
Log.i(TAG, "Public Key Info: ");
Log.i(TAG, "Algorithm = " + pubKey.getAlgorithm());
Log.i(TAG, "toString = " + pubKey.toString());
return pubKey;
}
public static PublicKey readPublicKeyFromPemFormat(Context context, int publicKeyId)
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
InputStream in = context.getResources().openRawResource(publicKeyId);
BufferedReader pemReader = new BufferedReader(new InputStreamReader(in));
StringBuffer content = new StringBuffer();
String line = null;
while ((line = pemReader.readLine()) != null) {
if (line.indexOf("-----BEGIN PUBLIC KEY-----") != -1) {
while ((line = pemReader.readLine()) != null) {
if (line.indexOf("-----END PUBLIC KEY") != -1) {
break;
}
content.append(line.trim());
}
break;
}
}
if (line == null) {
throw new IOException("PUBLIC KEY" + " not found");
}
Log.i("PUBLIC KEY: ", "PEM content = : " + content.toString());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.decode(content.toString(),
Base64.DEFAULT)));
}
public static byte[] readSignature(String input) throws IOException{
FileInputStream signStream = new FileInputStream(input);
byte[] signBytes = new byte[signStream.available()];
signStream.read(signBytes);
signStream.close();
return signBytes;
}
public static boolean verifySignature(String input, String algorithm, byte[] sign, PublicKey pubKey) throws Exception{
Signature sg = Signature.getInstance(algorithm);
sg.initVerify(pubKey);
Log.i(TAG, "Signature Object Info: ");
Log.i(TAG, "Algorithm = "+sg.getAlgorithm());
Log.i(TAG, "Provider = "+sg.getProvider());
FileInputStream in = new FileInputStream(input);
byte[] buff = new byte[in.available()];
in.read(buff);
in.close();
sg.update(buff);
boolean ok = sg.verify(sign);
Log.i(TAG, "Verify Processing Info: ");
Log.i(TAG, "Verification result = "+ok);
return ok;
}
public static boolean checkFileSignature(Context context, String filePath, String targetPath){
boolean valid = false;
unzip(filePath, targetPath);
try {
String filename = context.getResources().getString(R.string.versionFilename);
String fileXmlExt = context.getResources().getString(R.string.versionFilename_xml);
String fileSigExt = context.getResources().getString(R.string.versionFilename_sig);
PublicKey pubKey = RSAUtils.readPublicKeyFromPemFormat(context, R.raw.public_key);
byte[] sign = RSAUtils.readSignature(targetPath + filename + fileSigExt);
valid = RSAUtils.verifySignature(targetPath + filename + fileXmlExt, RSAUtils.SIGNATURE_ALGORITHM, sign, pubKey);
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return valid;
}
private static void unzip(String filePath, String targetPath) {
new File(targetPath).mkdirs();
try {
FileInputStream fin = new FileInputStream(filePath);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
Log.d(TAG, "Unzipping " + ze.getName());
if (ze.isDirectory()) {
_dirChecker(ze.getName(), targetPath);
} else {
FileOutputStream fout = new FileOutputStream(targetPath + ze.getName());
byte buffer[] = new byte[2048];
int count = 0;
while ((count = zin.read(buffer)) != -1) {
fout.write(buffer, 0, count);
}
zin.closeEntry();
fout.close();
}
}
zin.close();
fin.close();
} catch (Exception e) {
Log.e("Decompress", "unzip", e);
}
}
private static void _dirChecker(String dir, String location) {
File f = new File(location + dir);
if (!f.isDirectory()) {
f.mkdirs();
}
}
}