How to get Keystore fingerprint from code - java

I am currently struggling with getting some security to the Unity3d app I'm working on, and I want to add verification that apk file wasn't tampered with by some patchers. I know how to get keystore fingerprint from a built app (like keytool), but I have a hard time figuring out how to get that fingerprint from the code of my app during runtime to check that it is the same. I've gone through a lot of other threads to no success so far (like this: Get certificate fingerprint from android app)
Has anyone found solution how to do this or hint where I should start looking? Thanks in advance!

Modify the getCertificateSHA1Fingerprint function from the answer you linked to take Android Context as parameter. Get the Context from Unity and send it to this function then mark as static.
Java:
public final class CertificateSHA1Fingerprint
{
private static String getCertificateSHA1Fingerprint(Context mContext)
{
PackageManager pm = mContext.getPackageManager();
String packageName = mContext.getPackageName();
int flags = PackageManager.GET_SIGNATURES;
PackageInfo packageInfo = null;
try {
packageInfo = pm.getPackageInfo(packageName, flags);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Signature[] signatures = packageInfo.signatures;
byte[] cert = signatures[0].toByteArray();
InputStream input = new ByteArrayInputStream(cert);
CertificateFactory cf = null;
try {
cf = CertificateFactory.getInstance("X509");
} catch (CertificateException e) {
e.printStackTrace();
}
X509Certificate c = null;
try {
c = (X509Certificate) cf.generateCertificate(input);
} catch (CertificateException e) {
e.printStackTrace();
}
String hexString = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] publicKey = md.digest(c.getEncoded());
hexString = byte2HexFormatted(publicKey);
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
return hexString;
}
public static String byte2HexFormatted(byte[] arr)
{
StringBuilder str = new StringBuilder(arr.length * 2);
for (int i = 0; i < arr.length; i++)
{
String h = Integer.toHexString(arr[i]);
int l = h.length();
if (l == 1) h = "0" + h;
if (l > 2) h = h.substring(l - 2, l);
str.append(h.toUpperCase());
if (i < (arr.length - 1)) str.append(':');
}
return str.toString();
}
}
C#:
AndroidJavaClass unityClass;
AndroidJavaObject unityActivity;
AndroidJavaObject unityContext;
AndroidJavaClass customClass;
public string getCertificateSHA1Fingerprint()
{
//Replace with your full package name
string packageName = "com.example.CertificateSHA1Fingerprint";
unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
unityContext = unityActivity.Call<AndroidJavaObject>("getApplicationContext");
customClass = new AndroidJavaClass(packageName);
string result = customClass.CallStatic<string>("getCertificateSHA1Fingerprint", unityContext);
return result;
}
You only have to build the Java function with Android Studio and convert it into Jar or .AAR file then put it in your <ProjectName>Assets\Plugins\Android folder. The C# code will be able to communicate with it.

Related

Snmp code gives me this error Caused by: java.lang.NoClassDefFoundError: org/snmp4j/TransportMapping

i have been trying to apply commands of snmp at java on Ubuntu, i find an example code at stackoverflow and code's github link: https://github.com/jineshmathewt/snmpbulkwalk/blob/master/snmpbulkwalk/src/TestSNMP.java
But when i try to execute i m getting an error .
i would like to ask what am i doing wrong ? , to mention i can use get command on terminal and it works .
public class TestSNMP {
private static final String SNMPPORT = "161";
private static final int snmpVersion = SnmpConstants.version2c;
private int snmpTimeout = 500;
private int numRetries = 2;
public void doSNMPBulkWalk(String ipAddr, String commStr, String bulkOID, String operation) throws IOException {
Snmp snmp = new Snmp(new DefaultUdpTransportMapping());
UserTarget targetV3 = null;
CommunityTarget targetV2 = null;
UsmUser user = null;
PDU request = null;
snmp.listen();
Address add = new UdpAddress(ipAddr + "/" + SNMPPORT);
if (snmpVersion == SnmpConstants.version2c || snmpVersion == SnmpConstants.version1) {
targetV2 = new CommunityTarget();
targetV2.setCommunity(new OctetString(commStr));
targetV2.setAddress(add);
targetV2.setTimeout(snmpTimeout);
targetV2.setRetries(numRetries);
targetV2.setVersion(snmpVersion);
targetV2.setMaxSizeRequestPDU(65535);
}
if (snmpVersion == SnmpConstants.version2c) {
request = new PDU();
//request.setMaxRepetitions(100);
//request.setNonRepeaters(0);
}
request.setType(PDU.GETBULK);
OID oID = new OID(bulkOID);
request.add(new VariableBinding(oID));
OID rootOID = request.get(0).getOid();
VariableBinding vb, ar[];
List<TreeEvent> l = null;
TreeUtils treeUtils = new TreeUtils(snmp, new DefaultPDUFactory());
if (snmpVersion == SnmpConstants.version2c) {
targetV2.setCommunity(new OctetString(commStr));
if (operation.equalsIgnoreCase("bulkwalk")) {
OID[] rootOIDs = new OID[1];
rootOIDs[0] = rootOID;
l = treeUtils.walk(targetV2, rootOIDs);
} else {
l = treeUtils.getSubtree(targetV2, rootOID);
}
}
//System.out.println(l);
System.out.println("size="+l.size());
for(TreeEvent t : l){
VariableBinding[] vbs= t.getVariableBindings();
for (int i = 0; (vbs != null) && i < vbs.length; i++) {
vb = vbs[i];
String s = vb.toString();
System.out.println(s);
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Date d1 = new Date();
TestSNMP snmpTest = new TestSNMP();
try {
snmpTest.doSNMPBulkWalk(args[0], args[1], args[2], args[3]);
} catch (IOException e) {
e.printStackTrace();
}
Date d2 = new Date();
System.out.println("Time Elapsed=" + (d2.getTime() - d1.getTime()));
}
}
I think the snmp library jar is not included in the eclipse project. You have to download the snmp library jar from maven repository. Right click on the project and go to Properties -> Java Build Path -> Libraries and add those library jar there using Add External Jars.

Certificate Pinning on Android with Robospice

I'm reading about certificate pinning on Android and I'm confused. I'm not using okhttp or retrofit so I have to do it manually.
There is a tutorial here: https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#Android
where they are adding the certificate to list of trusted certificates. But there is also another tutorial when we're checking base64 of sha256 of the certificate installed on the server: https://medium.com/#appmattus/android-security-ssl-pinning-1db8acb6621e
Which approach is the correct one?
Why can't we just receive sha256 from the server in the header as browsers do and store it somewhere?
I would recommend this
https://www.paypal-engineering.com/2015/10/14/key-pinning-in-mobile-applications/
Android Method
The simplest approach is to use a JSEE-based method as shown below. This is the recommended approach for Android. The method’s input arguments are an HTTPS connection and a set of valid pins for the targeted URL.
private boolean validatePinning(HttpsURLConnection conn, Set<String> validPins) {
try {
Certificate[] certs = conn.getServerCertificates();
MessageDigest md = MessageDigest.getInstance("SHA-256");
for (Certificate cert : certs) {
X509Certificate x509Certificate = (X509Certificate) cert;
byte[] key = x509Certificate.getPublicKey().getEncoded();
md.update(key, 0, key.length);
byte[] hashBytes = md.digest();
StringBuffer hexHash = new StringBuffer();
for (int i = 0; i < hashBytes.length; i++) {
int k = 0xFF & hashBytes[i];
String tmp = (k<16)? "0" : "";
tmp += Integer.toHexString(0xFF & hashBytes[i]);
hexHash.append(tmp);
}
if (validPins.contains(hexHash.toString())) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return false;
}
The pins are declared as strings. For instance:
Declaring Key Pins
private static final Set<String> PINS = new HashSet<String>(Arrays.asList(
new String[]{
"996b510ce2380da9c738...87cb13c9ec409941",
"ba47e83b1ccf0939bb40d2...edf856ba892c06481a"}));
Leveraging the above method, here is an example showing how this can be put to use. The only relevant portion is highlighted below.
Example Using Key Pinning
protected String doInBackground(String... urls) {
try {
/** Test pinning given the target URL **/
/** for now use pre-defined endpoint URL instead or urls[0] **/
Log.i(LOG_TAG, "==> PinningTestTask launched.");
String dest = defaultEndpoint;
URL targetURL = new URL(dest);
HttpsURLConnection targetConnection = (HttpsURLConnection) targetURL.openConnection();
targetConnection.connect();
if (validatePinning(targetConnection, PINS)) {
final String updateText = "Key pinning succeded for: " + dest;
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(updateText);
}
});
} else {
final String updateText = "Key pinning failed for: " + dest;
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(updateText);
}
});
}
} catch (Exception e) {
e.printStackTrace();
final String updateText = "Key pinning failed for: " + dest + "\n" + e.toString();
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(updateText);
}
});
}
return null;
}

DCM4CHE, Network operations,Handling a C-Move call

Hi I'm trying to make a PACS server using Java. dcm4che appears to be quite popular. But I'm unable to find any good examples about it.
As a starting point I inspected dcmqrscp and it successfully stores a DICOM image. But I cannot manage to handle a C-MOVE call. Here's my CMove handler. It finds requested the DICOM file adds a URL and other stuff, it doesn't throw any exception yet client doesn't receive any files.
private final class CMoveSCPImpl extends BasicCMoveSCP {
private final String[] qrLevels;
private final QueryRetrieveLevel rootLevel;
public CMoveSCPImpl(String sopClass, String... qrLevels) {
super(sopClass);
this.qrLevels = qrLevels;
this.rootLevel = QueryRetrieveLevel.valueOf(qrLevels[0]);
}
#Override
protected RetrieveTask calculateMatches(Association as, PresentationContext pc, final Attributes rq, Attributes keys) throws DicomServiceException {
QueryRetrieveLevel level = QueryRetrieveLevel.valueOf(keys, qrLevels);
try {
level.validateRetrieveKeys(keys, rootLevel, relational(as, rq));
} catch (Exception e) {
e.printStackTrace();
}
String moveDest = rq.getString(Tag.MoveDestination);
final Connection remote = new Connection("reciverAE",as.getSocket().getInetAddress().getHostAddress(), 11113);
if (remote == null)
throw new DicomServiceException(Status.MoveDestinationUnknown, "Move Destination: " + moveDest + " unknown");
List<T> matches = DcmQRSCP.this.calculateMatches(keys);
if (matches.isEmpty())
return null;
AAssociateRQ aarq;
Association storeas = null;
try {
aarq = makeAAssociateRQ(as.getLocalAET(), moveDest, matches);
storeas = openStoreAssociation(as, remote, aarq);
} catch (Exception e) {
e.printStackTrace();
}
BasicRetrieveTask<T> retrieveTask = null;
retrieveTask = new BasicRetrieveTask<T>(Dimse.C_MOVE_RQ, as, pc, rq, matches, storeas, new BasicCStoreSCU<T>());
retrieveTask.setSendPendingRSPInterval(getSendPendingCMoveInterval());
return retrieveTask;
}
private Association openStoreAssociation(Association as, Connection remote, AAssociateRQ aarq)
throws DicomServiceException {
try {
return as.getApplicationEntity().connect(as.getConnection(),
remote, aarq);
} catch (Exception e) {
throw new DicomServiceException(
Status.UnableToPerformSubOperations, e);
}
}
private AAssociateRQ makeAAssociateRQ(String callingAET,
String calledAET, List<T> matches) {
AAssociateRQ aarq = new AAssociateRQ();
aarq.setCalledAET(calledAET);
aarq.setCallingAET(callingAET);
for (InstanceLocator match : matches) {
if (aarq.addPresentationContextFor(match.cuid, match.tsuid)) {
if (!UID.ExplicitVRLittleEndian.equals(match.tsuid))
aarq.addPresentationContextFor(match.cuid,
UID.ExplicitVRLittleEndian);
if (!UID.ImplicitVRLittleEndian.equals(match.tsuid))
aarq.addPresentationContextFor(match.cuid,
UID.ImplicitVRLittleEndian);
}
}
return aarq;
}
private boolean relational(Association as, Attributes rq) {
String cuid = rq.getString(Tag.AffectedSOPClassUID);
ExtendedNegotiation extNeg = as.getAAssociateAC().getExtNegotiationFor(cuid);
return QueryOption.toOptions(extNeg).contains(
QueryOption.RELATIONAL);
}
}
I added the code below to send a DICOM file as a response:
String cuid = rq.getString(Tag.AffectedSOPClassUID);
String iuid = rq.getString(Tag.AffectedSOPInstanceUID);
String tsuid = pc.getTransferSyntax();
try {
DcmQRSCP.this.as=as;
File f = new File("D:\\dcmqrscpTestDCMDir\\1.2.840.113619.2.30.1.1762295590.1623.978668949.886\\1.2.840.113619.2.30.1.1762295590.1623.978668949.887\\1.2.840.113619.2.30.1.1762295590.1623.978668949.888");
FileInputStream in = new FileInputStream(f);
InputStreamDataWriter data = new InputStreamDataWriter(in);
// !1! as.cmove(cuid,1,keys,tsuid,"STORESCU");
as.cstore(cuid,iuid,1,data,tsuid,rspHandlerFactory.createDimseRSPHandler(f));
} catch (Exception e) {
e.printStackTrace();
}
Throws this exception
org.dcm4che3.net.NoRoleSelectionException: No Role Selection for SOP Class 1.2.840.10008.5.1.4.1.2.2.2 - Study Root Query/Retrieve Information Model - MOVE as SCU negotiated
You should add a role to the application instance like:
applicationEntity.addTransferCapability(
new TransferCapability(null, "*", TransferCapability.Role.SCP, "*"));

How to pass args when calling one method from another

I have written the following code to create a key pair, store the private key locally, and then read the private key from that file.
When I try to call the methods savePrivateKey(); and retrievePrivateKey(); from testData(View view) I get an error that says (String[]) cannot be applied to (). I want to be able to call both of the above mentioned functions in testData(View view);
public class EncryptionActivity extends ActionBarActivity {
private static final String TAG = EncryptionActivity.class.getSimpleName();
TextView textPublicKey;
TextView textPrivateKey;
Button buttonTest;
TextView privateKey;
Integer n;
String FILENAME = "privateKey";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_encryption);
// output keys to screen
textPrivateKey = (TextView)findViewById(R.id.textPrivateKey);
textPrivateKey.setMovementMethod(new ScrollingMovementMethod());
// textPublicKey = (TextView)findViewById(R.id.textPublicKey);
}
private void AsymmetricAlgorithmRSA() {
// Generate key pair for 1024-bit RSA encryption and decryption
Key publicKey = null;
Key privateKey = null;
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
} catch (Exception e) {
Log.e(TAG, "RSA key pair error");
}
//textPublicKey.setText(String.valueOf(publicKey));
//textPrivateKey.setText(String.valueOf(privateKey));
}
public void savePrivateKey(String[] args) throws FileNotFoundException {
try {
// store private key locally
String string = String.valueOf(privateKey);
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
}
catch (Exception e) {
Log.e(TAG, "Error saving file.");
}
}
public void retrievePrivateKey(String[] args) throws FileNotFoundException {
try {
FileInputStream fis = openFileInput(FILENAME);
StringBuffer fileContent = new StringBuffer("");
byte[] buffer = new byte[1024];
while ((n = fis.read(buffer)) != -1) ;
{
fileContent.append(new String(buffer, 0, n));
}
textPrivateKey.setText(String.valueOf(fileContent));
}
catch(IOException e) {
Log.e(TAG, "Error opening file.");
}
}
public void testData(View view){
AsymmetricAlgorithmRSA();
savePrivateKey();
retrievePrivateKey();
}
Both savePrivateKey and retrievePrivateKey accept a String[], although they do not use them. Just drop these redundant parameter specifications and you should be fine:
public void savePrivateKey() throws FileNotFoundException {
// code here...
}
public void retrievePrivateKey() throws FileNotFoundException {
// code here...
}
savePrivateKey(); --> method which has no arguments. But you have implemented a method with arguments as String[] public void savePrivateKey(String[] args) throws FileNotFoundException.. Pass as String[] as argument or change the method signature.

*.rsa and *.sf manifest.mf calling from java class

I had resigned a jar file and runned it. However, it is closed itself immediately after opening. Is it possible to call infromation of *.rsa or *.sf or manifest.mf from java code to check it if changed or not, thank you.
Actually I found a method in the class of jar file and its returning certificates, that means yes in jar file there is a certificate control bridge, code is:
private Certificate[] XQ(et etProp) throws Exception{
System.out.println("Rg test 78");
String value = null;
Iterator iterator = etProp.af().iterator();
while (iterator.hasNext()) {
un.JI innerUn = (un.JI) iterator.next();
String certificateToUpperCase = innerUn.XQ().toUpperCase();
if (certificateToUpperCase != null && certificateToUpperCase.startsWith("META-INF/")
&& (certificateToUpperCase.endsWith(".RSA") || certificateToUpperCase.endsWith(".DSA"))) {
value = innerUn.XQ();
break;
}
}
if (value == null) {
System.out.println("Rg test 81");
qm.XQ((String) "Could not find certificates file");
return null;
} else {
System.out.println("Rg test 82");
byte[] arrayAf = etProp.af(value);
if (arrayAf == null) {
System.out.println("Rg test 83");
Object[] objectsArray = new Object[] { value };
return null;
} else {
System.out.println("Rg test 84");
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(arrayAf);
Collection collection;
try {
System.out.println("Rg test 85");
CertificateFactory certificateFactory = CertificateFactory
.getInstance("X.509");
collection = certificateFactory.generateCertificates(byteArrayInputStream);
} catch (CertificateException ex) {
qm.XQ((String) String.format(
"Could not parse certificate data: %s",
new Object[] { ex.toString() }));
return null;
}
Certificate[] certificates = new Certificate[collection.size()];
int i = 0;
Certificate certificate;
for (Iterator iterator1 = collection.iterator(); iterator1.hasNext(); certificates[i++] = certificate) {
System.out.println("Rg test 87");
certificate = (Certificate) iterator1.next();
}
return certificates;
}
}
}
It is very nice move to protect jar file from cracking.

Categories