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.io.IOException; 024import java.util.List; 025import java.util.TreeMap; 026 027import org.jivesoftware.smackx.omemo.element.OmemoBundleElement; 028import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; 029import org.jivesoftware.smackx.omemo.internal.OmemoDevice; 030import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; 031import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil; 032 033import org.whispersystems.libsignal.IdentityKey; 034import org.whispersystems.libsignal.IdentityKeyPair; 035import org.whispersystems.libsignal.InvalidKeyException; 036import org.whispersystems.libsignal.ecc.Curve; 037import org.whispersystems.libsignal.ecc.ECPublicKey; 038import org.whispersystems.libsignal.state.PreKeyBundle; 039import org.whispersystems.libsignal.state.PreKeyRecord; 040import org.whispersystems.libsignal.state.SessionRecord; 041import org.whispersystems.libsignal.state.SignedPreKeyRecord; 042import org.whispersystems.libsignal.util.KeyHelper; 043 044/** 045 * Concrete implementation of the KeyUtil for an implementation using the Signal library. 046 * 047 * @author Paul Schaub 048 */ 049public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, 050 SessionRecord, ECPublicKey, PreKeyBundle> { 051 052 @Override 053 public IdentityKeyPair generateOmemoIdentityKeyPair() { 054 return KeyHelper.generateIdentityKeyPair(); 055 } 056 057 @Override 058 public TreeMap<Integer, PreKeyRecord> generateOmemoPreKeys(int currentPreKeyId, int count) { 059 List<PreKeyRecord> preKeyRecords = KeyHelper.generatePreKeys(currentPreKeyId, count); 060 TreeMap<Integer, PreKeyRecord> map = new TreeMap<>(); 061 for (PreKeyRecord p : preKeyRecords) { 062 map.put(p.getId(), p); 063 } 064 return map; 065 } 066 067 @Override 068 public SignedPreKeyRecord generateOmemoSignedPreKey(IdentityKeyPair identityKeyPair, int currentPreKeyId) 069 throws CorruptedOmemoKeyException { 070 try { 071 return KeyHelper.generateSignedPreKey(identityKeyPair, currentPreKeyId); 072 } catch (InvalidKeyException e) { 073 throw new CorruptedOmemoKeyException(e); 074 } 075 } 076 077 @Override 078 public SignedPreKeyRecord signedPreKeyFromBytes(byte[] data) throws IOException { 079 if (data == null) return null; 080 return new SignedPreKeyRecord(data); 081 } 082 083 @Override 084 public byte[] signedPreKeyToBytes(SignedPreKeyRecord signedPreKeyRecord) { 085 return signedPreKeyRecord.serialize(); 086 } 087 088 @Override 089 public SessionRecord rawSessionFromBytes(byte[] data) throws IOException { 090 if (data == null) return null; 091 return new SessionRecord(data); 092 } 093 094 @Override 095 public byte[] rawSessionToBytes(SessionRecord session) { 096 return session.serialize(); 097 } 098 099 @Override 100 public IdentityKeyPair identityKeyPairFromBytes(byte[] data) throws CorruptedOmemoKeyException { 101 if (data == null) return null; 102 try { 103 return new IdentityKeyPair(data); 104 } catch (InvalidKeyException e) { 105 throw new CorruptedOmemoKeyException(e); 106 } 107 } 108 109 @Override 110 public IdentityKey identityKeyFromBytes(byte[] data) throws CorruptedOmemoKeyException { 111 if (data == null) return null; 112 try { 113 return new IdentityKey(data, 0); 114 } catch (InvalidKeyException e) { 115 throw new CorruptedOmemoKeyException(e); 116 } 117 } 118 119 @Override 120 public ECPublicKey ellipticCurvePublicKeyFromBytes(byte[] data) throws CorruptedOmemoKeyException { 121 if (data == null) return null; 122 try { 123 return Curve.decodePoint(data, 0); 124 } catch (InvalidKeyException e) { 125 throw new CorruptedOmemoKeyException(e); 126 } 127 } 128 129 @Override 130 public byte[] preKeyToBytes(PreKeyRecord preKeyRecord) { 131 return preKeyRecord.serialize(); 132 } 133 134 @Override 135 public PreKeyRecord preKeyFromBytes(byte[] bytes) throws IOException { 136 if (bytes == null) return null; 137 return new PreKeyRecord(bytes); 138 } 139 140 @Override 141 public PreKeyBundle bundleFromOmemoBundle(OmemoBundleElement bundle, OmemoDevice contact, int preKeyId) 142 throws CorruptedOmemoKeyException { 143 return new PreKeyBundle(0, 144 contact.getDeviceId(), 145 preKeyId, 146 BUNDLE.preKeyPublic(bundle, preKeyId), 147 BUNDLE.signedPreKeyId(bundle), 148 BUNDLE.signedPreKeyPublic(bundle), 149 BUNDLE.signedPreKeySignature(bundle), 150 BUNDLE.identityKey(bundle)); 151 } 152 153 @Override 154 public byte[] signedPreKeySignatureFromKey(SignedPreKeyRecord signedPreKey) { 155 return signedPreKey.getSignature(); 156 } 157 158 @Override 159 public int signedPreKeyIdFromKey(SignedPreKeyRecord signedPreKey) { 160 return signedPreKey.getId(); 161 } 162 163 @Override 164 public byte[] identityKeyPairToBytes(IdentityKeyPair identityKeyPair) { 165 return identityKeyPair.serialize(); 166 } 167 168 @Override 169 public IdentityKey identityKeyFromPair(IdentityKeyPair identityKeyPair) { 170 return identityKeyPair.getPublicKey(); 171 } 172 173 @Override 174 public byte[] identityKeyForBundle(IdentityKey identityKey) { 175 return identityKey.getPublicKey().serialize(); 176 } 177 178 @Override 179 public byte[] identityKeyToBytes(IdentityKey identityKey) { 180 return identityKey.serialize(); 181 } 182 183 @Override 184 public byte[] preKeyPublicKeyForBundle(ECPublicKey preKey) { 185 return preKey.serialize(); 186 } 187 188 @Override 189 public byte[] preKeyForBundle(PreKeyRecord preKeyRecord) { 190 return preKeyRecord.getKeyPair().getPublicKey().serialize(); 191 } 192 193 @Override 194 public byte[] signedPreKeyPublicForBundle(SignedPreKeyRecord signedPreKey) { 195 return signedPreKey.getKeyPair().getPublicKey().serialize(); 196 } 197 198 @Override 199 public OmemoFingerprint getFingerprintOfIdentityKey(IdentityKey identityKey) { 200 if (identityKey == null) { 201 return null; 202 } 203 204 String fp = identityKey.getFingerprint(); 205 // Cut "(byte)0x" prefixes, remove spaces and commas, cut first two digits. 206 fp = fp.replace("(byte)0x", "").replace(",", "") 207 .replace(" ", "").substring(2); 208 return new OmemoFingerprint(fp); 209 } 210 211 @Override 212 public OmemoFingerprint getFingerprintOfIdentityKeyPair(IdentityKeyPair identityKeyPair) { 213 if (identityKeyPair == null) { 214 return null; 215 } 216 return getFingerprintOfIdentityKey(identityKeyPair.getPublicKey()); 217 } 218}