/**
*
*/
package org.commcare.android.database.app.models;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import org.commcare.android.crypt.CryptUtil;
import org.commcare.android.storage.framework.MetaField;
import org.commcare.android.storage.framework.Persisted;
import org.commcare.android.storage.framework.Persisting;
import org.commcare.android.storage.framework.Table;
import org.javarosa.core.util.PropertyUtils;
/**
* @author ctsims
*
*/
@Table("user_key_records")
public class UserKeyRecord extends Persisted {
public static final String META_USERNAME = "username";
public static final String META_SANDBOX_ID = "sandbox_id";
public static final String META_KEY_STATUS = "status";
/** This is a normal sandbox record that is ready to be used **/
public static final int TYPE_NORMAL = 1;
/** This is a record representing a legacy database that should be transfered over **/
public static final int TYPE_LEGACY_TRANSITION = 2;
/** This is a new record that hasn't been evaluated for usage yet **/
public static final int TYPE_NEW = 3;
/** This is a new record that hasn't been evaluated for usage yet **/
public static final int TYPE_PENDING_DELETE = 4;
@Persisting(1)
@MetaField(META_USERNAME)
private String username;
@Persisting(2)
private String passwordHash;
@Persisting(3)
private byte[] encryptedKey;
@Persisting(4)
private Date validFrom;
@Persisting(5)
private Date validTo;
@Persisting(6)
/** The unique ID of the data sandbox covered by this key **/
@MetaField(META_SANDBOX_ID)
private String uuid;
@MetaField(META_KEY_STATUS)
@Persisting(7)
private int type;
/**
* Serialization Only!
*/
public UserKeyRecord() {
}
public UserKeyRecord(String username, String passwordHash, byte[] encryptedKey, Date validFrom, Date validTo, String uuid) {
this(username, passwordHash, encryptedKey, validFrom, validTo, uuid, TYPE_NORMAL);
}
public UserKeyRecord(String username, String passwordHash, byte[] encryptedKey, Date validFrom, Date validTo, String uuid, int type) {
this.username = username;
this.passwordHash = passwordHash;
this.encryptedKey = encryptedKey;
this.validFrom = validFrom;
this.validTo = validTo;
this.uuid = uuid;
this.type = type;
}
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @return the passwordHash
*/
public String getPasswordHash() {
return passwordHash;
}
/**
* @return the encryptedKey
*/
public byte[] getEncryptedKey() {
return encryptedKey;
}
/**
* @return the validFrom
*/
public Date getValidFrom() {
return validFrom;
}
/**
* @return the validTo
*/
public Date getValidTo() {
return validTo;
}
/**
* @return the uuid
*/
public String getUuid() {
return uuid;
}
public int getType() {
return type;
}
public static String generatePwdHash(String pwd) {
String alg = "sha1";
int saltLength = 6;
int hashLength = 41;
String salt = PropertyUtils.genGUID(saltLength).toLowerCase();
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
BigInteger number = new BigInteger(1, md.digest((salt+pwd).getBytes()));
String hashed = number.toString(16);
while(hashed.length() < hashLength) {
hashed = "0" + hashed;
}
return alg + "$" + salt + "$" + hashed;
}
public void setType(int typeNormal) {
this.type = typeNormal;
}
public boolean isPasswordValid(String password) {
try {
String hash = this.getPasswordHash();
if(hash.contains("$")) {
String alg = "sha1";
String salt = hash.split("\\$")[1];
String check = hash.split("\\$")[2];
MessageDigest md = MessageDigest.getInstance("SHA-1");
BigInteger number = new BigInteger(1, md.digest((salt+password).getBytes()));
String hashed = number.toString(16);
while(hashed.length() < check.length()) {
hashed = "0" + hashed;
}
if(hash.equals(alg + "$" + salt + "$" + hashed)) {
return true;
}
}
return false;
} catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException("SHA-1 support not present!");
}
}
public byte[] unWrapKey(String password) {
if(isPasswordValid(password)) {
return CryptUtil.unWrapKey(getEncryptedKey(), password);
} else {
//throw exception?
return null;
}
}
public boolean isCurrentlyValid() {
//currentTimeMillis is UTC
Date today = new Date(System.currentTimeMillis());
//Our validity dates are all in UTC
if(validFrom.before(today) && (validTo == null || (validTo.getTime() != Long.MAX_VALUE && validTo.after(today)))) {
return true;
}
return false;
}
}