2017-07-30 22:31:29 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Copyright 2017 Paul Schaub
|
|
|
|
*
|
|
|
|
* 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.jivesoftware.smackx.ciphers;
|
|
|
|
|
|
|
|
import java.security.InvalidAlgorithmParameterException;
|
|
|
|
import java.security.InvalidKeyException;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import java.security.NoSuchProviderException;
|
|
|
|
import java.security.SecureRandom;
|
|
|
|
import javax.crypto.Cipher;
|
|
|
|
import javax.crypto.KeyGenerator;
|
|
|
|
import javax.crypto.NoSuchPaddingException;
|
|
|
|
import javax.crypto.SecretKey;
|
2017-07-31 14:57:43 +02:00
|
|
|
import javax.crypto.spec.IvParameterSpec;
|
2017-07-30 22:31:29 +02:00
|
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
|
|
|
|
public abstract class AesGcmNoPadding {
|
|
|
|
|
|
|
|
public static final String keyType = "AES";
|
|
|
|
public static final String cipherMode = "AES/GCM/NoPadding";
|
|
|
|
|
|
|
|
private final int length;
|
|
|
|
protected final Cipher cipher;
|
|
|
|
protected final byte[] key, iv, keyAndIv;
|
|
|
|
|
2017-08-05 15:29:01 +02:00
|
|
|
protected AesGcmNoPadding(int bits, int MODE) throws NoSuchAlgorithmException, NoSuchProviderException,
|
2017-07-30 22:31:29 +02:00
|
|
|
NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException {
|
2017-07-30 23:32:00 +02:00
|
|
|
this.length = bits;
|
|
|
|
int bytes = bits / 8;
|
2017-07-30 22:31:29 +02:00
|
|
|
|
|
|
|
KeyGenerator keyGenerator = KeyGenerator.getInstance(keyType);
|
2017-07-30 23:32:00 +02:00
|
|
|
keyGenerator.init(bits);
|
2017-07-30 22:31:29 +02:00
|
|
|
key = keyGenerator.generateKey().getEncoded();
|
|
|
|
|
|
|
|
SecureRandom secureRandom = new SecureRandom();
|
2017-07-30 23:32:00 +02:00
|
|
|
iv = new byte[bytes];
|
2017-07-30 22:31:29 +02:00
|
|
|
secureRandom.nextBytes(iv);
|
|
|
|
|
2017-07-30 23:32:00 +02:00
|
|
|
keyAndIv = new byte[2 * bytes];
|
|
|
|
System.arraycopy(key, 0, keyAndIv, 0, bytes);
|
|
|
|
System.arraycopy(iv, 0, keyAndIv, bytes, bytes);
|
2017-07-30 22:31:29 +02:00
|
|
|
|
|
|
|
cipher = Cipher.getInstance(cipherMode, "BC");
|
2017-07-31 14:21:49 +02:00
|
|
|
SecretKey keySpec = new SecretKeySpec(key, keyType);
|
2017-07-31 14:57:43 +02:00
|
|
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
2017-08-05 15:29:01 +02:00
|
|
|
cipher.init(MODE, keySpec, ivSpec);
|
2017-07-30 22:31:29 +02:00
|
|
|
}
|
|
|
|
|
2017-08-05 15:29:01 +02:00
|
|
|
public static AesGcmNoPadding createEncryptionKey(String cipherName)
|
2017-08-04 15:08:16 +02:00
|
|
|
throws NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException,
|
|
|
|
InvalidAlgorithmParameterException {
|
|
|
|
|
|
|
|
switch (cipherName) {
|
|
|
|
case Aes128GcmNoPadding.NAMESPACE:
|
2017-08-05 15:29:01 +02:00
|
|
|
return new Aes128GcmNoPadding(Cipher.ENCRYPT_MODE);
|
2017-08-04 15:08:16 +02:00
|
|
|
case Aes256GcmNoPadding.NAMESPACE:
|
2017-08-05 15:29:01 +02:00
|
|
|
return new Aes256GcmNoPadding(Cipher.ENCRYPT_MODE);
|
2017-08-04 15:08:16 +02:00
|
|
|
default: throw new NoSuchAlgorithmException("Invalid cipher.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-05 15:29:01 +02:00
|
|
|
/**
|
|
|
|
* Create a new AES key.
|
|
|
|
* @param key key
|
|
|
|
* @param iv iv
|
|
|
|
* @param MODE cipher mode (Cipher.ENCRYPT_MODE / Cipher.DECRYPT_MODE)
|
|
|
|
* @throws NoSuchPaddingException
|
|
|
|
* @throws NoSuchAlgorithmException
|
|
|
|
* @throws NoSuchProviderException
|
|
|
|
* @throws InvalidAlgorithmParameterException
|
|
|
|
* @throws InvalidKeyException
|
|
|
|
*/
|
|
|
|
public AesGcmNoPadding(byte[] key, byte[] iv, int MODE) throws NoSuchPaddingException, NoSuchAlgorithmException,
|
2017-07-30 22:31:29 +02:00
|
|
|
NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException {
|
2017-07-31 12:08:18 +02:00
|
|
|
this.length = key.length * 8;
|
2017-07-30 22:31:29 +02:00
|
|
|
this.key = key;
|
|
|
|
this.iv = iv;
|
|
|
|
|
2017-07-31 12:08:18 +02:00
|
|
|
keyAndIv = new byte[key.length + iv.length];
|
|
|
|
System.arraycopy(key, 0, keyAndIv, 0, key.length);
|
|
|
|
System.arraycopy(iv, 0, keyAndIv, key.length, iv.length);
|
2017-07-30 22:31:29 +02:00
|
|
|
|
|
|
|
cipher = Cipher.getInstance(cipherMode, "BC");
|
|
|
|
SecretKeySpec keySpec = new SecretKeySpec(key, keyType);
|
2017-07-31 14:57:43 +02:00
|
|
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
2017-08-05 15:29:01 +02:00
|
|
|
cipher.init(MODE, keySpec, ivSpec);
|
2017-07-30 22:31:29 +02:00
|
|
|
}
|
|
|
|
|
2017-08-05 15:29:01 +02:00
|
|
|
public static AesGcmNoPadding createDecryptionKey(String namespace, byte[] serialized)
|
2017-08-04 15:08:16 +02:00
|
|
|
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException,
|
|
|
|
InvalidKeyException, NoSuchPaddingException {
|
|
|
|
|
|
|
|
switch (namespace) {
|
|
|
|
case Aes128GcmNoPadding.NAMESPACE:
|
2017-08-05 15:29:01 +02:00
|
|
|
return new Aes128GcmNoPadding(serialized, Cipher.DECRYPT_MODE);
|
2017-08-04 15:08:16 +02:00
|
|
|
case Aes256GcmNoPadding.NAMESPACE:
|
2017-08-05 15:29:01 +02:00
|
|
|
return new Aes256GcmNoPadding(serialized, Cipher.DECRYPT_MODE);
|
2017-08-04 15:08:16 +02:00
|
|
|
default: throw new NoSuchAlgorithmException("Invalid cipher.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-30 22:31:29 +02:00
|
|
|
public byte[] getKeyAndIv() {
|
|
|
|
return keyAndIv.clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
public byte[] getKey() {
|
|
|
|
return key.clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
public byte[] getIv() {
|
|
|
|
return iv.clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getLength() {
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Cipher getCipher() {
|
|
|
|
return cipher;
|
|
|
|
}
|
|
|
|
|
|
|
|
public abstract String getNamespace();
|
|
|
|
|
|
|
|
public static byte[] copyOfRange(byte[] source, int start, int end) {
|
|
|
|
byte[] copy = new byte[end - start];
|
|
|
|
System.arraycopy(source, start, copy, 0, end - start);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
}
|