001/** 002 * 003 * Copyright 2017 Paul Schaub 004 * 005 * This file is part of smack-omemo-signal. 006 * 007 * smack-omemo-signal is free software; you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation; either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with this program; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021package org.jivesoftware.smackx.omemo.signal; 022 023import java.util.ArrayList; 024import java.util.HashMap; 025import java.util.List; 026import java.util.logging.Level; 027import java.util.logging.Logger; 028 029import org.jivesoftware.smackx.omemo.OmemoManager; 030import org.jivesoftware.smackx.omemo.OmemoStore; 031import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; 032 033import org.jxmpp.jid.impl.JidCreate; 034import org.jxmpp.stringprep.XmppStringprepException; 035import org.whispersystems.libsignal.IdentityKey; 036import org.whispersystems.libsignal.IdentityKeyPair; 037import org.whispersystems.libsignal.InvalidKeyIdException; 038import org.whispersystems.libsignal.SessionCipher; 039import org.whispersystems.libsignal.SignalProtocolAddress; 040import org.whispersystems.libsignal.ecc.ECPublicKey; 041import org.whispersystems.libsignal.state.IdentityKeyStore; 042import org.whispersystems.libsignal.state.PreKeyBundle; 043import org.whispersystems.libsignal.state.PreKeyRecord; 044import org.whispersystems.libsignal.state.PreKeyStore; 045import org.whispersystems.libsignal.state.SessionRecord; 046import org.whispersystems.libsignal.state.SessionStore; 047import org.whispersystems.libsignal.state.SignedPreKeyRecord; 048import org.whispersystems.libsignal.state.SignedPreKeyStore; 049 050/** 051 * Class that adapts libsignal-protocol-java's Store classes to the OmemoStore class. 052 * 053 * @author Paul Schaub 054 */ 055public class SignalOmemoStoreConnector 056 implements IdentityKeyStore, SessionStore, PreKeyStore, SignedPreKeyStore { 057 058 private static final Logger LOGGER = Logger.getLogger(SignalOmemoStoreConnector.class.getName()); 059 060 private final OmemoManager omemoManager; 061 private final OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> 062 omemoStore; 063 064 public SignalOmemoStoreConnector(OmemoManager omemoManager, OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> store) { 065 this.omemoManager = omemoManager; 066 this.omemoStore = store; 067 } 068 069 @Override 070 public IdentityKeyPair getIdentityKeyPair() { 071 try { 072 return omemoStore.loadOmemoIdentityKeyPair(omemoManager); 073 } catch (CorruptedOmemoKeyException e) { 074 LOGGER.log(Level.SEVERE, "getIdentityKeyPair has failed: " + e, e); 075 return null; 076 } 077 } 078 079 /** 080 * We don't use this. 081 * @return dummy 082 */ 083 @Override 084 public int getLocalRegistrationId() { 085 return 0; 086 } 087 088 @Override 089 public void saveIdentity(SignalProtocolAddress signalProtocolAddress, IdentityKey identityKey) { 090 try { 091 omemoStore.storeOmemoIdentityKey(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress), identityKey); 092 } catch (XmppStringprepException e) { 093 throw new AssertionError(e); 094 } 095 } 096 097 @Override 098 public boolean isTrustedIdentity(SignalProtocolAddress signalProtocolAddress, IdentityKey identityKey) { 099 // Disable internal trust management. Instead we use OmemoStore.isTrustedOmemoIdentity() before encrypting for a 100 // recipient. 101 return true; 102 } 103 104 @Override 105 public PreKeyRecord loadPreKey(int i) throws InvalidKeyIdException { 106 PreKeyRecord pr = omemoStore.loadOmemoPreKey(omemoManager, i); 107 if (pr == null) { 108 throw new InvalidKeyIdException("No PreKey with Id " + i + " found!"); 109 } 110 return pr; 111 } 112 113 @Override 114 public void storePreKey(int i, PreKeyRecord preKeyRecord) { 115 omemoStore.storeOmemoPreKey(omemoManager, i, preKeyRecord); 116 } 117 118 @Override 119 public boolean containsPreKey(int i) { 120 try { 121 return (loadPreKey(i) != null); 122 } catch (InvalidKeyIdException e) { 123 LOGGER.log(Level.WARNING, "containsPreKey has failed: " + e.getMessage()); 124 return false; 125 } 126 } 127 128 @Override 129 public void removePreKey(int i) { 130 omemoStore.removeOmemoPreKey(omemoManager, i); 131 } 132 133 @Override 134 public SessionRecord loadSession(SignalProtocolAddress signalProtocolAddress) { 135 try { 136 SessionRecord s = omemoStore.loadRawSession(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress)); 137 return (s != null ? s : new SessionRecord()); 138 } catch (XmppStringprepException e) { 139 throw new AssertionError(e); 140 } 141 } 142 143 @Override 144 public List<Integer> getSubDeviceSessions(String s) { 145 HashMap<Integer, SessionRecord> contactsSessions; 146 try { 147 contactsSessions = omemoStore.loadAllRawSessionsOf(omemoManager, JidCreate.bareFrom(s)); 148 } catch (XmppStringprepException e) { 149 throw new AssertionError(e); 150 } 151 if (contactsSessions != null) { 152 return new ArrayList<>(contactsSessions.keySet()); 153 } 154 return new ArrayList<>(); 155 } 156 157 @Override 158 public void storeSession(SignalProtocolAddress signalProtocolAddress, SessionRecord sessionRecord) { 159 try { 160 omemoStore.storeRawSession(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress), sessionRecord); 161 } catch (XmppStringprepException e) { 162 throw new AssertionError(e); 163 } 164 } 165 166 @Override 167 public boolean containsSession(SignalProtocolAddress signalProtocolAddress) { 168 try { 169 return omemoStore.containsRawSession(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress)); 170 } catch (XmppStringprepException e) { 171 throw new AssertionError(e); 172 } 173 } 174 175 @Override 176 public void deleteSession(SignalProtocolAddress signalProtocolAddress) { 177 try { 178 omemoStore.removeRawSession(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress)); 179 } catch (XmppStringprepException e) { 180 throw new AssertionError(e); 181 } 182 } 183 184 @Override 185 public void deleteAllSessions(String s) { 186 try { 187 omemoStore.removeAllRawSessionsOf(omemoManager, JidCreate.bareFrom(s)); 188 } catch (XmppStringprepException e) { 189 throw new AssertionError(e); 190 } 191 } 192 193 @Override 194 public SignedPreKeyRecord loadSignedPreKey(int i) throws InvalidKeyIdException { 195 SignedPreKeyRecord spkr = omemoStore.loadOmemoSignedPreKey(omemoManager, i); 196 if (spkr == null) { 197 throw new InvalidKeyIdException("No SignedPreKey with Id " + i + " found!"); 198 } 199 return spkr; 200 } 201 202 @Override 203 public List<SignedPreKeyRecord> loadSignedPreKeys() { 204 HashMap<Integer, SignedPreKeyRecord> signedPreKeyRecordHashMap = omemoStore.loadOmemoSignedPreKeys(omemoManager); 205 List<SignedPreKeyRecord> signedPreKeyRecordList = new ArrayList<>(); 206 signedPreKeyRecordList.addAll(signedPreKeyRecordHashMap.values()); 207 return signedPreKeyRecordList; 208 } 209 210 @Override 211 public void storeSignedPreKey(int i, SignedPreKeyRecord signedPreKeyRecord) { 212 omemoStore.storeOmemoSignedPreKey(omemoManager, i, signedPreKeyRecord); 213 } 214 215 @Override 216 public boolean containsSignedPreKey(int i) { 217 try { 218 return loadSignedPreKey(i) != null; 219 } catch (InvalidKeyIdException e) { 220 LOGGER.log(Level.WARNING, "containsSignedPreKey has failed: " + e.getMessage()); 221 return false; 222 } 223 } 224 225 @Override 226 public void removeSignedPreKey(int i) { 227 omemoStore.removeOmemoSignedPreKey(omemoManager, i); 228 } 229}