File encryption utilities

This commit is contained in:
jendib 2013-08-20 18:06:08 +02:00
parent 0bc658a396
commit 00b00f0d0c
7 changed files with 172 additions and 45 deletions

View File

@ -47,6 +47,12 @@ public class User {
@Column(name = "USE_PASSWORD_C", nullable = false, length = 100) @Column(name = "USE_PASSWORD_C", nullable = false, length = 100)
private String password; private String password;
/**
* User's private key.
*/
@Column(name = "USE_PRIVATEKEY_C", nullable = false, length = 100)
private String privateKey;
/** /**
* Email address. * Email address.
*/ */
@ -256,6 +262,22 @@ public class User {
public void setDeleteDate(Date deleteDate) { public void setDeleteDate(Date deleteDate) {
this.deleteDate = deleteDate; this.deleteDate = deleteDate;
} }
/**
* Getter de privateKey.
* @return privateKey
*/
public String getPrivateKey() {
return privateKey;
}
/**
* Setter de privateKey.
* @param privateKey privateKey
*/
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
@Override @Override
public String toString() { public String toString() {

View File

@ -0,0 +1,91 @@
package com.sismics.docs.core.util;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* Encryption utilities.
*
* @author bgamard
*/
public class EncryptionUtil {
/**
* Salt.
*/
private static final String SALT = "LEpxZmm2SMu2PeKzPNrar2rhVAS6LrrgvXKeL9uyXC4vgKHg";
/**
* Generate a private key.
*
* @return New random private key
* @throws NoSuchAlgorithmException
*/
public static String generatePrivateKey() throws NoSuchAlgorithmException {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
return new BigInteger(176, random).toString(32);
}
/**
* Encrypt an InputStream using the specified private key.
*
* @param is InputStream to encrypt
* @param privateKey Private key
* @return Encrypted stream
* @throws Exception
*/
public static InputStream encryptStream(InputStream is, String privateKey) throws Exception {
checkBouncyCastleProvider();
return new CipherInputStream(is, getCipher(privateKey, Cipher.ENCRYPT_MODE));
}
/**
* Decrypt an InputStream using the specified private key.
*
* @param is InputStream to encrypt
* @param privateKey Private key
* @return Encrypted stream
* @throws Exception
*/
public static InputStream decryptStream(InputStream is, String privateKey) throws Exception {
checkBouncyCastleProvider();
return new CipherInputStream(is, getCipher(privateKey, Cipher.DECRYPT_MODE));
}
/**
* Initialize a Cipher.
*
* @param privateKey Private key
* @param mode Mode (encrypt or decrypt)
* @return Cipher
* @throws Exception
*/
private static Cipher getCipher(String privateKey, int mode) throws Exception {
PBEKeySpec keySpec = new PBEKeySpec(privateKey.toCharArray(), SALT.getBytes(), 2000, 256);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
SecretKey desKey = skf.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING");
cipher.init(mode, desKey);
return cipher;
}
/**
* Initialize the Bouncy Castle provider if necessary.
*/
private static void checkBouncyCastleProvider() {
if (Security.getProvider("BouncyCastleProvider") == null) {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}
}
}

View File

@ -3,18 +3,11 @@ package com.sismics.docs.core.util;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.List; import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import net.sourceforge.tess4j.Tesseract; import net.sourceforge.tess4j.Tesseract;
@ -28,7 +21,6 @@ import org.imgscalr.Scalr.Mode;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.google.common.io.ByteStreams;
import com.sismics.docs.core.model.jpa.Document; import com.sismics.docs.core.model.jpa.Document;
import com.sismics.docs.core.model.jpa.File; import com.sismics.docs.core.model.jpa.File;
import com.sismics.util.ImageUtil; import com.sismics.util.ImageUtil;
@ -207,41 +199,4 @@ public class FileUtil {
thumbnailFile.delete(); thumbnailFile.delete();
} }
} }
// Security.insertProviderAt(new BouncyCastleProvider(), 1);
// String key = "pwd";
//
// FileInputStream fis = new FileInputStream("plain.jpg");
// FileOutputStream fos = new FileOutputStream("encrypted.jpg");
// encrypt(key, fis, fos);
//
// FileInputStream fis2 = new FileInputStream("encrypted.jpg");
// FileOutputStream fos2 = new FileOutputStream("decrypted.jpg");
// decrypt(key, fis2, fos2);
public static void encrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.ENCRYPT_MODE, is, os);
}
public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os);
}
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
PBEKeySpec keySpec = new PBEKeySpec(key.toCharArray(), "salt".getBytes(), 2000, 256);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
SecretKey desKey = skf.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING");
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(Cipher.ENCRYPT_MODE, desKey);
CipherInputStream cis = new CipherInputStream(is, cipher);
ByteStreams.copy(cis, os);
} else if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, desKey);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
ByteStreams.copy(is, cos);
}
}
} }

View File

@ -0,0 +1,51 @@
package com.sismics.docs.core.util;
import java.io.InputStream;
import junit.framework.Assert;
import org.bouncycastle.util.io.Streams;
import org.junit.Test;
import com.google.common.base.Strings;
import com.google.common.io.ByteStreams;
/**
* Test of the encryption utilities.
*
* @author bgamard
*/
public class TestEncryptUtil {
/**
* Test private key.
*/
String pk = "OnceUponATime";
@Test
public void generatePrivateKeyTest() throws Exception {
String key = EncryptionUtil.generatePrivateKey();
System.out.println(key);
Assert.assertFalse(Strings.isNullOrEmpty(key));
}
@Test
public void encryptStreamTest() throws Exception {
InputStream inputStream = EncryptionUtil.encryptStream(this.getClass().getResourceAsStream("/file/udhr.pdf"), pk);
byte[] encryptedData = Streams.readAll(inputStream);
byte[] assertData = Streams.readAll(this.getClass().getResourceAsStream("/file/udhr_encrypted.pdf"));
Assert.assertTrue(ByteStreams.equal(
ByteStreams.newInputStreamSupplier(encryptedData),
ByteStreams.newInputStreamSupplier(assertData)));
}
@Test
public void decryptStreamTest() throws Exception {
InputStream inputStream = EncryptionUtil.decryptStream(this.getClass().getResourceAsStream("/file/udhr_encrypted.pdf"), pk);
byte[] encryptedData = Streams.readAll(inputStream);
byte[] assertData = Streams.readAll(this.getClass().getResourceAsStream("/file/udhr.pdf"));
Assert.assertTrue(ByteStreams.equal(
ByteStreams.newInputStreamSupplier(encryptedData),
ByteStreams.newInputStreamSupplier(assertData)));
}
}

Binary file not shown.

Binary file not shown.

View File

@ -7,6 +7,7 @@ import com.sismics.docs.core.dao.jpa.UserDao;
import com.sismics.docs.core.dao.jpa.dto.UserDto; import com.sismics.docs.core.dao.jpa.dto.UserDto;
import com.sismics.docs.core.model.jpa.AuthenticationToken; import com.sismics.docs.core.model.jpa.AuthenticationToken;
import com.sismics.docs.core.model.jpa.User; import com.sismics.docs.core.model.jpa.User;
import com.sismics.docs.core.util.EncryptionUtil;
import com.sismics.docs.core.util.jpa.PaginatedList; import com.sismics.docs.core.util.jpa.PaginatedList;
import com.sismics.docs.core.util.jpa.PaginatedLists; import com.sismics.docs.core.util.jpa.PaginatedLists;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
@ -28,6 +29,8 @@ import javax.ws.rs.*;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -76,6 +79,11 @@ public class UserResource extends BaseResource {
user.setUsername(username); user.setUsername(username);
user.setPassword(password); user.setPassword(password);
user.setEmail(email); user.setEmail(email);
try {
user.setPrivateKey(EncryptionUtil.generatePrivateKey());
} catch (NoSuchAlgorithmException e) {
throw new ServerException("PrivateKeyError", "Error while generating a private key", e);
}
user.setCreateDate(new Date()); user.setCreateDate(new Date());
if (localeId == null) { if (localeId == null) {