/*
* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.androidsdk.ssl;
import android.util.Base64;
import org.json.JSONException;
import org.json.JSONObject;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
/**
* Represents a X509 Certificate fingerprint.
*/
public class Fingerprint {
public enum HashType { SHA1, SHA256 }
private byte[] mBytes;
private HashType mHashType;
private String mDisplayableHexRepr;
public Fingerprint(byte[] bytes, HashType hashType) {
this.mBytes = bytes;
this.mHashType = hashType;
this.mDisplayableHexRepr = null;
}
public static Fingerprint newSha256Fingerprint(X509Certificate cert) throws CertificateException {
return new Fingerprint(
CertUtil.generateSha256Fingerprint(cert),
HashType.SHA256
);
}
public static Fingerprint newSha1Fingerprint(X509Certificate cert) throws CertificateException {
return new Fingerprint(
CertUtil.generateSha1Fingerprint(cert),
HashType.SHA1
);
}
public HashType getType() {
return mHashType;
}
public byte[] getBytes() {
return mBytes;
}
public String getBytesAsHexString() {
if (mDisplayableHexRepr == null) {
mDisplayableHexRepr = CertUtil.fingerprintToHexString(mBytes);
}
return mDisplayableHexRepr;
}
public JSONObject toJson() throws JSONException {
JSONObject obj = new JSONObject();
obj.put("bytes", Base64.encodeToString(getBytes(), Base64.DEFAULT));
obj.put("hash_type", mHashType.toString());
return obj;
}
public static Fingerprint fromJson(JSONObject obj) throws JSONException {
String hashTypeStr = obj.getString("hash_type");
byte[] fingerprintBytes = Base64.decode(obj.getString("bytes"), Base64.DEFAULT);
final HashType hashType;
if ("SHA256".equalsIgnoreCase(hashTypeStr)) {
hashType = HashType.SHA256;
} else if ("SHA1".equalsIgnoreCase(hashTypeStr)) {
hashType = HashType.SHA1;
} else {
throw new JSONException("Unrecognized hash type: " + hashTypeStr);
}
return new Fingerprint(fingerprintBytes, hashType);
}
public boolean matchesCert(X509Certificate cert) throws CertificateException {
Fingerprint o = null;
switch (mHashType) {
case SHA256:
o = Fingerprint.newSha256Fingerprint(cert);
break;
case SHA1:
o = Fingerprint.newSha1Fingerprint(cert);
break;
}
return equals(o);
}
public String toString() {
return String.format("Fingerprint{type: '%s', fingeprint: '%s'}", mHashType.toString(), getBytesAsHexString());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Fingerprint that = (Fingerprint) o;
if (!Arrays.equals(mBytes, that.mBytes)) return false;
return mHashType == that.mHashType;
}
@Override
public int hashCode() {
int result = mBytes != null ? Arrays.hashCode(mBytes) : 0;
result = 31 * result + (mHashType != null ? mHashType.hashCode() : 0);
return result;
}
}