/* * * Panbox - encryption for cloud storage * Copyright (C) 2014-2015 by Fraunhofer SIT and Sirrix AG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Additonally, third party code may be provided with notices and open source * licenses from communities and third parties that govern the use of those * portions, and any licenses granted hereunder do not alter any rights and * obligations you may have under such open source licenses, however, the * disclaimer of warranty and limitation of liability provisions of the GPLv3 * will apply to all the product. * */ package org.panbox.core.keymgmt; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SignatureException; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.TreeMap; import javax.crypto.SecretKey; import org.panbox.core.Utils; import org.panbox.core.crypto.CryptCore; import org.panbox.core.crypto.Signable; import org.panbox.core.crypto.SignatureHelper; import org.panbox.core.exception.SerializationException; import org.panbox.core.exception.SymmetricKeyDecryptionException; import org.panbox.core.exception.SymmetricKeyEncryptionException; /** * @author dukan * */ public class ShareKeyDB implements Signable { // Mapping of Version to Map of DevicePublicKey-Fingerprint to encrypted // symmetric Sharekey private TreeMap<Integer, ShareKeyDBEntry> shareKeys; // private int latest = -1; private String signer; private byte[] signature; @Override public boolean equals(Object obj) { if (obj == null) return false; if (obj == this) return true; if (obj.getClass() != getClass()) return false; ShareKeyDB o = (ShareKeyDB) obj; if (o.signer == null && signer == null) { return Utils.valueEquals(shareKeys, o.shareKeys); } else { return o.signer != null && o.signer.equals(signer) && Arrays.equals(signature, o.signature) && Utils.valueEquals(shareKeys, o.shareKeys); } } @Override public int hashCode() { int hc = 15; int hashMultiplier = 59; hc = hc * hashMultiplier + (shareKeys == null ? 0 : shareKeys.hashCode()) + (signer == null ? 0 : signer.hashCode()); if (signature != null) { for (int i = 0; i < signature.length; i++) { hc += signature[i]; } } return hc; } public ShareKeyDB() { this.shareKeys = new TreeMap<Integer, ShareKeyDBEntry>(); } ShareKeyDBEntry add(SecretKey sk, Collection<PublicKey> pubKeys) throws SymmetricKeyEncryptionException { int version = getLatestVersion() + 1; String algo = sk.getAlgorithm(); ShareKeyDBEntry result = new ShareKeyDBEntry(algo, version); byte[] shareKey = sk.getEncoded(); for (PublicKey pKey : pubKeys) { byte[] byteArray = CryptCore.encryptSymmetricKey(shareKey, pKey); result.addEncryptedKey(byteArray, pKey); } add(version, result); return result; } ShareKeyDBEntry add(SecretKey sk) throws SymmetricKeyEncryptionException { int version = getLatestVersion() + 1; String algo = sk.getAlgorithm(); ShareKeyDBEntry result = new ShareKeyDBEntry(algo, version); byte[] shareKey = sk.getEncoded(); ShareKeyDBEntry shareKeyDBEntry = this.shareKeys.get((version - 1)); if (shareKeyDBEntry == null) { throw new RuntimeException( "Trying to add new version of ShareKey when there was no previous version!"); } Iterator<PublicKey> pubKeys = shareKeyDBEntry.getKeyIterator(); while (pubKeys.hasNext()) { PublicKey pKey = (PublicKey) pubKeys.next(); byte[] byteArray = CryptCore.encryptSymmetricKey(shareKey, pKey); result.addEncryptedKey(byteArray, pKey); add(version, result); } return result; } void addDevice(PublicKey oldDevicePubKey, PrivateKey oldDevicePrivKey, PublicKey newDevicePubKey) throws SymmetricKeyDecryptionException, SymmetricKeyEncryptionException { for (ShareKeyDBEntry entry : shareKeys.values()) { byte[] encSK = entry.getEncryptedKey(oldDevicePubKey); if (encSK != null) { SecretKey sk = CryptCore.decryptSymmertricKey(encSK, oldDevicePrivKey); entry.addEncryptedKey(sk, newDevicePubKey); } } } public void removeDevice(PublicKey deviceKey) { for (ShareKeyDBEntry entry : shareKeys.values()) { entry.removeEncryptedKey(deviceKey); } } void add(int version, ShareKeyDBEntry entry) { shareKeys.put(version, entry); } public int size() { return this.shareKeys.size(); } public ShareKeyDBEntry getEntry(int version) { return this.shareKeys.get(version); } public Iterator<Integer> getKeyIterator() { return this.shareKeys.keySet().iterator(); } public byte[] getEntry(int version, PublicKey key) { return shareKeys.get(version).getEncryptedKey(key); } /** * @return either the ShareKeyDBEntryObject containing the latest version * ShareKeys or <code>null</code> if no ShareKeys have been * generated so far */ public ShareKeyDBEntry getLastEntry() { if (this.size() > 0) { return shareKeys.get(getLatestVersion()); } else { return null; } } private int getLatestVersion() { int latest = -1; if (!shareKeys.isEmpty()) { latest = shareKeys.lastKey(); } return latest; } @Override public byte[] serialize() throws SerializationException { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); for (Integer i : shareKeys.keySet()) { os.write(i.intValue()); os.write(shareKeys.get(i).serialize()); } return os.toByteArray(); } catch (IOException e) { throw new SerializationException("Could not serialize ShareKeyDB", e); } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("ShareKeyDB:\n"); for (Integer i : shareKeys.keySet()) { sb.append("\t" + i.intValue() + "\n"); sb.append("\t" + shareKeys.get(i) + "\n"); } return sb.toString(); } String getSigner() { return this.signer; } void setSigner(String signer) { this.signer = signer; } byte[] getSignature() { return this.signature; } void sign(PrivateKey privateKey, String signer) throws SignatureException { setSigner(signer); try { this.signature = SignatureHelper.sign(this, privateKey); } catch (Exception e) { throw new SignatureException("Could not sign ShareKeyDB", e); } } public void setSignature(byte[] signature) { this.signature = signature; } ShareKeyDB get(Collection<PublicKey> keys) { ShareKeyDB result = new ShareKeyDB(); Collection<ShareKeyDBEntry> entries = shareKeys.values(); for (ShareKeyDBEntry entry : entries) { ShareKeyDBEntry e = new ShareKeyDBEntry(entry.getAlgorithm(), entry.getVersion()); for (PublicKey publicKey : keys) { byte[] encKey = entry.getEncryptedKey(publicKey); if (encKey != null) { e.addEncryptedKey(encKey, publicKey); ; } } result.add(e.getVersion(), e); } return result; } }