I have tried using the solution provided in this link.
I am getting following error when i tried reading subject alternative names of X.509 Certificate
java.lang.NoSuchMethodError: org.bouncycastle.asn1.ASN1InputStream.readObject()Lorg/bouncycastle/asn1/DERObject;
At below line of code
ASN1InputStream decoder = new ASN1InputStream((byte[]) item.toArray());
DEREncodable encoded = decoder.readObject();
.der file is used to create certificate as follows.
X509Certificate cert=null;
fis = new FileInputStream(file.getAbsoluteFile()); //.der file
bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
try{
cert = cf.generateCertificate(bis);
}
catch (CertificateException e) {
e.printStackTrace();
}
List list=getSubjectAlternativeNames((X509Certificate) cert);
Below is the solution i got from the link mentioned above.
public static List<String> getSubjectAlternativeNames(X509Certificate certificate) {
List<String> identities = new ArrayList<String>();
try {
Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
// Check that the certificate includes the SubjectAltName extension
if (altNames == null)
return Collections.emptyList();
// Use the type OtherName to search for the certified server name
for (List item : altNames) {
Integer type = (Integer) item.get(0);
if (type == 0)
// Type OtherName found so return the associated value
try {
// Value is encoded using ASN.1 so decode it to get the server's identity
ASN1InputStream decoder = new ASN1InputStream((byte[]) item.toArray()[1]);
DEREncodable encoded = decoder.readObject();
encoded = ((DERSequence) encoded).getObjectAt(1);
encoded = ((DERTaggedObject) encoded).getObject();
encoded = ((DERTaggedObject) encoded).getObject();
String identity = ((DERUTF8String) encoded).getString();
// Add the decoded server name to the list of identities
identities.add(identity);
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
// log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
}
catch (Exception e) {
// log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
e.printStackTrace();
}
// Other types are not good for XMPP so ignore them
//log.warn("SubjectAltName of invalid type found: " + certificate);
}
}
catch (CertificateParsingException e) {
e.printStackTrace();
// log.error("Error parsing SubjectAltName in certificate: " + certificate + "\r\nerror:" + e.getLocalizedMessage(),e);
}
return identities;
}
Is it that i have not used proper .jar file?
.jar i have used is --> bcprov-jdk16-1.45.jar
Suggest me where i have gone wrong.
I tried with your code for me it is working, I tested with a certificate exported from internet explorer
Internet Explorer -> Tools -> Internet Options -> Content -> Certificates -> Untrusted Publishers -> www.google.com
I exported this as ".cer", I made few changes to your code
public static List<String> getSubjectAlternativeNames(X509Certificate certificate) {
List<String> identities = new ArrayList<String>();
try {
Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
if (altNames == null)
return Collections.emptyList();
for (List item : altNames) {
Integer type = (Integer) item.get(0);
if (type == 0 || type == 2){
try {
ASN1InputStream decoder=null;
if(item.toArray()[1] instanceof byte[])
decoder = new ASN1InputStream((byte[]) item.toArray()[1]);
else if(item.toArray()[1] instanceof String)
identities.add( (String) item.toArray()[1] );
if(decoder==null) continue;
DEREncodable encoded = decoder.readObject();
encoded = ((DERSequence) encoded).getObjectAt(1);
encoded = ((DERTaggedObject) encoded).getObject();
encoded = ((DERTaggedObject) encoded).getObject();
String identity = ((DERUTF8String) encoded).getString();
identities.add(identity);
}
catch (UnsupportedEncodingException e) {
log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
}
catch (Exception e) {
log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
}
}else{
log.warn("SubjectAltName of invalid type found: " + certificate);
}
}
}
catch (CertificateParsingException e) {
log.error("Error parsing SubjectAltName in certificate: " + certificate + "\r\nerror:" + e.getLocalizedMessage(),e);
}
return identities;
}
I saved the file to c:\aa1.cer
X509Certificate cert=null;
FileInputStream fis = new FileInputStream("c:\\aa1.cer");
BufferedInputStream bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
if (bis.available() > 0)
try{
cert = (X509Certificate)cf.generateCertificate(bis);
}
catch (CertificateException e) {
e.printStackTrace();
}
System.out.println(CertificateInfo.getSubjectAlternativeNames(cert));
I got the output as [www.google.com, google.com]
Please check your certificate, I think the problem is your certificate
Many examples use hard-coded integers. For readability, I much prefer to use:
GeneralName.dNSName = 2
GeneralName.iPAddress = 7
... etc
The code:
public static String[] parseHostNames(X509Certificate cert) {
List<String> hostNameList = new ArrayList<>();
try {
Collection<List<?>> altNames = cert.getSubjectAlternativeNames();
if (altNames != null) {
for(List<?> altName : altNames) {
if(altName.size()< 2) continue;
switch((Integer)altName.get(0)) {
case GeneralName.dNSName:
case GeneralName.iPAddress:
Object data = altName.get(1);
if (data instanceof String) {
hostNameList.add(((String)data));
}
break;
default:
}
}
}
System.out.println("Parsed hostNames: " + String.join(", ", hostNameList));
} catch(CertificateParsingException | IOException e) {
System.err.println("Can't parse hostNames from this cert.");
e.printStackTrace();
}
return hostNameList.toArray(new String[hostNameList.size()]);
}
Note: The accepted answer checks for byte[], but won't compile on my system. I found some other examples using byte[] by calling new ASN1InputStream((byte[])data).readObject();, but I have no certificate to test it with, so I've removed it from my example.
Related
How do i write file as UTF8? i already set the system property but not working.
Below is the sample code.
SmbFileOutputStream sfos = null;
try {
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(wipDomain,wipUsername,wipPassword);
System.setProperty("jcifs.encoding", "UTF8");
logger.info("Path: " +path);
SmbFile sFile = new SmbFile(path, auth);
sfos = new SmbFileOutputStream(sFile);
sfos.write(content.getBytes());
return true;
} catch (IOException e) {
logger.error(e.getMessage());
return false;
} finally {
if (sfos != null){
try {
sfos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
content.getBytes("UTF-8")
Encodes this String into a sequence of bytes using the given charset, storing the result into a new byte array.
This method always replaces malformed-input and unmappable-character sequences with this charset's default replacement byte array. The CharsetEncoder class should be used when more control over the encoding process is required.
I try to send valid request to REST API which uses oAuth. I keep receiving respond : "Invalid signature"
Here's steps I do to generate request:
Build Request:
public String buildRequest() {
ArrayList<String> params = new ArrayList<>(generateParams());
params.add("oauth_signature=" + sign(buildSignatureBaseString()));
Collections.sort(params);
return join(params.toArray(template), "&");
}
Creating Signature Base String:
public String buildSignatureBaseString(){
StringBuilder builder = new StringBuilder();
builder.append(METHOD);
builder.append("&");
builder.append(percentEncoding(URL));
builder.append("&");
builder.append(percentEncoding(join(generateParams().toArray(template), "&")));
return builder.toString();
}
Generating parameters sorted in natural order:
private ArrayList<String> generateParams() {
ArrayList<String> params = new ArrayList<>();
params.add("oauth_consumer_key=" + "...");
params.add("oauth_signature_method=HMAC-SHA1");
params.add("oauth_timestamp=" + Long.valueOf(System.currentTimeMillis() / 1000).toString());
params.add("oauth_nonce=" + getNonce());
params.add("oauth_version=1.0");
params.add("format=json");
params.add("method=foods.search");
params.add("search_expression=pasta");
Collections.sort(params);
return params;
}
Creating Signature Base String:
public String buildSignatureBaseString(){
StringBuilder builder = new StringBuilder();
builder.append(METHOD);
builder.append("&");
builder.append(percentEncoding(URL));
builder.append("&");
builder.append(percentEncoding(join(generateParams().toArray(template), "&")));
return builder.toString();
}
Generating signature with HMAC-SHA1:
public String sign(String sbs) {
String key = <SharedSecret> + "&";
SecretKeySpec sk = new SecretKeySpec(key.getBytes(Charset.forName("UTF-8")), ALGORITHM);
try {
Mac m = Mac.getInstance(ALGORITHM);
m.init(sk);
byte[] hmacEncoded = m.doFinal(sbs.getBytes(Charset.forName("UTF-8")));
byte[] base64Encoded = Base64.encode(hmacEncoded, Base64.DEFAULT);
return Uri.encode(new String(base64Encoded, Charset.forName("UTF-8")));
} catch (java.security.NoSuchAlgorithmException e) {
Log.w("FatSecret_TEST FAIL", e.getMessage());
return null;
} catch (java.security.InvalidKeyException e) {
Log.w("FatSecret_TEST FAIL", e.getMessage());
return null;
}
}
Could someone more experienced in this matter help?
Regards
The param entries from generateParams all are in the form tag=value. Your sign method seems only to return a value.
And: Are you sure the sign method does not throw? I this case you would return null, which you should check in the caller method and only add it to the params if it is not null
how to check if the file content is same as the revision in server perforce JAVA API. Before updating any file into perforce depot, I want to check is there any difference in content of local file and the depot file. if there is no difference then ignore to submit that file.
I think you want the getDiffFiles() method:
https://www.perforce.com/perforce/r15.1/manuals/p4java-javadoc/com/perforce/p4java/impl/mapbased/client/Client.html#getDiffFiles
Alternatively, for the specific thing you're doing (not submitting unchanged files), just use the "leaveUnchanged" submit option rather than doing the same work yourself.
Yes simple to do. Just generate a MD5 hash of the original file and before updating again generate a MD5 hash of the new file.
Now compare the hashes of both the files. If both are same, then the contents of both the files are same and if not then they are different and you are good to update.
Here is an utility to generate and check MD5 easily,
public class MD5Utils {
private static final String TAG = "MD5";
public static boolean checkMD5(String md5, File updateFile) {
if (TextUtils.isEmpty(md5) || updateFile == null) {
Log.e(TAG, "MD5 string empty or updateFile null");
return false;
}
String calculatedDigest = calculateMD5(updateFile);
if (calculatedDigest == null) {
Log.e(TAG, "calculatedDigest null");
return false;
}
Log.v(TAG, "Calculated digest: " + calculatedDigest);
Log.v(TAG, "Provided digest: " + md5);
return calculatedDigest.equalsIgnoreCase(md5);
}
public static String calculateMD5(File updateFile) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "Exception while getting digest", e);
return null;
}
InputStream is;
try {
is = new FileInputStream(updateFile);
} catch (FileNotFoundException e) {
Log.e(TAG, "Exception while getting FileInputStream", e);
return null;
}
byte[] buffer = new byte[8192];
int read;
try {
while ((read = is.read(buffer)) > 0) {
digest.update(buffer, 0, read);
}
byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
String output = bigInt.toString(16);
// Fill to 32 chars
output = String.format("%32s", output).replace(' ', '0');
return output;
} catch (IOException e) {
throw new RuntimeException("Unable to process file for MD5", e);
} finally {
try {
is.close();
} catch (IOException e) {
Log.e(TAG, "Exception on closing MD5 input stream", e);
}
}
}
}
I can unzip the 1st and 2nd entry of a zip file I am reading from the web, but then I get the MalformedInputException error. The zip file consists of unicode file names of mp3 files. I created the zip file that I placed on the web using Winzip (I tried both v11 and V18).
The mp3 files are all at the 'root' level in the zip file, i.e. not stored in subfolders.
I tried first with ZipInputStream. The last attempt (below) is with ArchiveInputStream. (I noticed that ArchiveInputStream didn't have a closeEntry() method like ZipInputStream - not that it made any difference).
The error always occurs on the line that gets the next entry.
while ((entry = (ZipArchiveEntry)zipStream.getNextEntry()) != null)
The code is
private void unizpMediaFile(String mediaDirectory, String zipFileURL) {
InputStream inputStream = null;
ArchiveInputStream zipStream = null;
ArchiveEntry entry = null;
try {
// make sure can write to (probably) sd card
File mediaFileDirectory = createMediaDirectory(mediaDirectory);
if (mediaFileDirectory == null)
return;
inputStream = getHttpInputStream(zipFileURL);
if (inputStream == null) {
return;
}
zipStream = new ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.ZIP,new BufferedInputStream(
inputStream) );
while ((entry = (ZipArchiveEntry)zipStream.getNextEntry()) != null) {
Log.i(TAG,"Entry:" + entry.getName());
if (entry.isDirectory()) {
if (false == new File( mediaFileDirectory.getAbsoluteFile()
+ File.separator + entry.getName()).mkdirs()) {
return;
}
} else {
OutputStream out = new FileOutputStream(mediaFileDirectory.getAbsoluteFile()
+ File.separator + entry.getName());
int size;
byte[] buffer = new byte[4096];
FileOutputStream outStream = new FileOutputStream(
mediaFileDirectory.getAbsoluteFile()
+ File.separator + entry.getName());
BufferedOutputStream bufferOut = new BufferedOutputStream(
outStream, buffer.length);
while ((size = zipStream.read(buffer, 0, buffer.length)) != -1) {
bufferOut.write(buffer, 0, size);
}
bufferOut.flush();
bufferOut.close();
out.close();
Log.i(TAG,"Entry:" + entry.getName() + " closed.");
}
}
maintOpDetails.append(res.getString(R.string.load_complete));
updateLoadDetails(maintOpDetails.toString() );
} catch (FileNotFoundException e) {
Log.e(TAG, "unizpMediaFile" + e.toString());
storeErrorMessage(res.getString(R.string.error_reading_media_zip_file,
zipFileURL, e.toString()));
} catch (IOException e) {
Log.e(TAG, "unizpMediaFile" + e.toString());
storeErrorMessage(res.getString(R.string.error_reading_media_zip_file,
zipFileURL, e.toString()));
} catch (ArchiveException e) {
Log.e(TAG, "unizpMediaFile" + e.toString());
storeErrorMessage(res.getString(R.string.error_reading_media_zip_file,
zipFileURL, e.toString()));
}
finally {
if (inputStream != null){ try {inputStream.close();} catch (Exception e){} }
if (zipStream != null){ try {zipStream.close();} catch (Exception e){} }
}
}
private InputStream getHttpInputStream(String url) {
HttpResponse response;
InputStream is = null;
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httppost = new HttpGet("http://" + url);
try {
response = httpClient.execute(httppost);
HttpEntity ht = response.getEntity();
BufferedHttpEntity buf;
buf = new BufferedHttpEntity(ht);
is = buf.getContent();
} catch (ClientProtocolException e) {
Log.e(TAG, "getHttpInputStream" + e.toString());
storeErrorMessage(res.getString(R.string.error_reading_file_at_url,
url, e.toString()));
} catch (ConnectTimeoutException cte) {
Log.e(TAG, "getHttpInputStream" + cte.toString());
storeErrorMessage(res.getString(R.string.connect_timetout_error, url));
} catch (IOException e) {
Log.e(TAG, "getHttpInputStream" + e.toString());
storeErrorMessage(res.getString(R.string.error_reading_file_at_url,
url, e.toString()));
}
return is;
}
From the log I get
I/LoadLanguageLessonService(3102): Entry:evet.mp3
I/LoadLanguageLessonService(3102): Entry:evet.mp3 closed.
I/LoadLanguageLessonService(3102): Entry:hay?r.mp3
I/LoadLanguageLessonService(3102): Entry:hay?r.mp3 closed.
E/LoadLanguageLessonService(3102): unizpMediaFilejava.nio.charset.MalformedInputException: Length: 1
(The cut/paste from the log to here caused the unicode filename values to be converted to the '?' you see above.)
I checked out various SO postings with no luck.
Any ideas?
Some followup
I modified my code to first download the zip file to my phone and then unzip it from there. No luck doing it that way either.
I also used the following code
ZipFile zipFile = null;
try {
zipFile = new ZipFile(zipFilename);
Enumeration<?> enu = zipFile.entries();
while (enu.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) enu.nextElement();
String name = zipEntry.getName();
long size = zipEntry.getSize();
long compressedSize = zipEntry.getCompressedSize();
Log.e(TAG, String.format("name: %-20s | size: %6d | compressed size: %6d\n",
name, size, compressedSize));
}
} catch (IOException e) {
e.printStackTrace();
throw e;
}
to list all the entries in the zip file and found that the unicode characters all show up as a small black diamond with a question mark inside (after cut/paste into SO the characters show up just with the ? mark).
I also downloaded AndroZip and WinZip for Android and viewed the zip file via both apps on my phone. Again the unicode file names were corrupted.
At this point I am stuck. I think I will shift gears and see about downloading the files one by one.
I want to calculate the CRC or MD5 of a specific file (Activity) in my Application (within my APK) so that I can compare that value in another file and make sure that the first file has not been tampered with.
Can I do that? Is so, can you guide me with it?
Example:
Let say I have file A.java and B.java. I want to calculate A.java CRC32/MD5 and store this value in B.java so that when B.java executes it recalaculates A.java and compares it to the known value
You can't do this. There are no separate class files on Android, you get a single DEX file with all classes and libraries compiled in. You have to compute the hash of the classes.dex file and store it in a resource file, because putting it in a class file will change the overall hash value. However, if I decompile your app and changes your classes.dex, I can also changes the resources, so that doesn't really offer any real protection. Of course, you can try to obfuscate or hide the value to make it harder, but some tools will look for CRC/MessageDigest references and simply hook them to return the same value every time.
Get the contents of A.java into a string using a java.io.BufferedReader and proceed as follows:
public byte[] getMD5(String fileAContents) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(fileAContents.getBytes());
return messageDigest.digest();
}
public static void calculate(Context context) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
ZipInputStream fis = get(context);
System.out.println("fis: " + fis);
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = fis.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
};
byte[] mdbytes = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < mdbytes.length; i++) {
sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Digest(in hex format):: " + sb.toString());
//convert the byte to hex format method 2
StringBuffer hexString = new StringBuffer();
for (int i=0;i<mdbytes.length;i++) {
String hex=Integer.toHexString(0xff & mdbytes[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
System.out.println("Digest(in hex format):: " + hexString.toString());
if(fis!=null){
fis.close();
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static ZipInputStream get(Context context){
// Get the path to the apk container.
String apkPath = context.getApplicationInfo().sourceDir;
JarFile containerJar = null;
try {
// Open the apk container as a jar..
containerJar = new JarFile(apkPath);
// Look for the "classes.dex" entry inside the container.
ZipEntry zzz = containerJar.getEntry("classes.dex");
// If this entry is present in the jar container
if (zzz != null) {
System.out.println("long " + zzz.getCrc());
// Get an Input Stream for the "classes.dex" entry
InputStream in = containerJar.getInputStream(zzz);
ZipInputStream zin = new ZipInputStream(in);
return zin;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (containerJar != null)
try {
containerJar.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}