・ ** Nous développons avec JavaVM (6 ou version ultérieure) **, ce qui est loin d'être le dernier. -Dans le fichier de propriétés, ** certaines valeurs d'éléments telles que "mot de passe" sont chiffrées avec OpenSSL (Base64) **. -Les éléments cibles à déchiffrer peuvent augmenter ou diminuer **. -Je n'aime pas déchiffrer les éléments à déchiffrer un par un **.
Je ne veux pas m'embêter avec le décryptage. Je veux faire fonctionner un bean comme s'il était défini depuis le début en texte brut. En d'autres termes, si vous faites Dawn avec Bean, vous voulez l'utiliser avec Pan. (vocabulaire)
Obtenir un chiffrement compatible OpenSSL avec Java / PHP
6 ou version ultérieure. Cet article est conforme à 6 pour le moment.
Puisque nous utilisons Base64, nous utiliserons ApacheCommonsCodec.
Tout d'abord, je veux convertir avec JAXB, c'est donc un fichier de propriétés au format XML.
Annotations personnalisées pour les beans.
Un bean qui contient les valeurs du fichier de propriétés.
Comme le titre l'indique, c'est une classe qui fera de vous une casserole si vous le faites avec Dawn.
Ce sont toutes les ressources utilisées par Java. Séparément, préparez le mot de passe principal utilisé pour le cryptage / décryptage dans votre cerveau. La méthode de cryptage est le "mode CBC AES à clé 128 bits".
La cible de déchiffrement est «xxUser» et «xxPass». Placez-le dans un répertoire qui a un chemin de classe.
property.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<!--Cible de décryptage "xxUser"-->
<!--C'est une chaîne de caractères dans laquelle le texte brut "hogeyama" est chiffré avec le mot de passe "yakisoba".-->
<xxUser>U2FsdGVkX1/k+6dPcXrci4AbyQ0TNtytubkVFCxzcF4=</xxUser>
<!--Cible de décryptage "xxPass"-->
<!--Il s'agit d'une chaîne de caractères dans laquelle le texte brut "mot de passe hogeyamano" est crypté avec le mot de passe "yakisoba".-->
<xxPass>U2FsdGVkX19XLVe01kx2ahoKVKnSXLhBQ2aiRrdUlbjgtKu1IXD3EuYDSADab5vA</xxPass>
<!--Texte brut-->
<miscItem1>hoge</miscItem1>
<!--Texte brut-->
<miscItem2>fuga</miscItem2>
</root>
Créez la chaîne de caractères chiffrée réelle avec la commande openssl (ci-dessous) ou l '[URL de référence] ci-dessus (https://qiita.com/kazuhidet/items/509bee2c3a109ff6ea61).
bash
$echo [texte brut]| openssl enc -e -aes-128-cbc -base64 -k [mot de passe principal]
Annotation chiffrée
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Encrypted {}
À ce stade, ajoutez une annotation chiffrée au champ qui contient la valeur chiffrée.
PropertyBean
public class PropertyBean {
@Encrypted
private String xxUser = null;
@Encrypted
private String xxPass= null;
private String miscItem1 = null;
private String miscItem2 = null;
public String getXxUser() {
return xxUser;
}
public void setXxUser(String xxUser) {
this.xxUser = xxUser;
}
public String getXxPass() {
return xxPass;
}
public void setXxPass(String xxPass) {
this.xxPass = xxPass;
}
public String getMiscItem1() {
return miscItem1;
}
public void setMiscItem1(String miscItem1) {
this.miscItem1 = miscItem1;
}
public String getMiscItem2() {
return miscItem2;
}
public void setMiscItem2(String miscItem2) {
this.miscItem2 = miscItem2;
}
}
Classe EncDecConverter
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class EncDecConverter<T> {
private T t = null;
private String password = null;
private Charset charset = null;
@SuppressWarnings("unused")
private EncDecConverter() {}
public EncDecConverter(T t,String password){
this.t = t;
this.password = password;
charset = Charset.defaultCharset();
}
public EncDecConverter(T t,String password,String charsetName){
this.t = t;
this.password = password;
charset = Charset.forName(charsetName);
}
public boolean decrypt(){
return convert(true);
}
public boolean encrypt(){
return convert(false);
}
private boolean convert(boolean processDecrypt){
if(t == null || password == null){
return false;
}
Field[] fs = t.getClass().getDeclaredFields();
String value = "";
try {
for(Field f : fs){
f.setAccessible(true);
if(f.getAnnotation(Encrypted.class) != null){
value = (processDecrypt?decrypt((String)f.get(t),password):encrypt((String)f.get(t),password));
f.set(t,removeLineSeparator(value));
}
}
}catch(Throwable e) {
e.printStackTrace();
return false;
}
return true;
}
private String removeLineSeparator(String s) {
if(s == null) {
return "";
}
return s.replaceAll("[\r]*[\n]*$", "");
}
private boolean getKeyAndGenerateIv(String password, byte[] salt, byte[] key_bytes, byte[] iv_bytes) {
byte[] password_bytes = password.getBytes(charset);
int length = password_bytes.length + salt.length;
ByteBuffer byte_buffer = ByteBuffer.allocate(length);
byte_buffer.put(password_bytes);
byte_buffer.put(salt);
byte_buffer.rewind();
byte[] byte_array = new byte[length];
byte_buffer.get(byte_array);
try {
System.arraycopy(MessageDigest.getInstance("MD5").digest(byte_array), 0, key_bytes, 0, key_bytes.length);
}catch (NoSuchAlgorithmException e ) {
e.printStackTrace();
return false;
}
length = password_bytes.length + salt.length + key_bytes.length;
byte_buffer = ByteBuffer.allocate(length);
byte_buffer.put(key_bytes);
byte_buffer.put(password_bytes);
byte_buffer.put(salt);
byte_buffer.rewind();
byte_array = new byte[length];
byte_buffer.get(byte_array);
try {
System.arraycopy(MessageDigest.getInstance("MD5").digest(byte_array), 0, iv_bytes, 0, iv_bytes.length);
}catch (NoSuchAlgorithmException e ) {
e.printStackTrace();
return false;
}
return true;
}
private String encrypt(String plaintext, String password) throws Throwable{
// Generate random salt.
byte[] random_bytes = new byte[8];
new SecureRandom().nextBytes(random_bytes);
byte[] key_bytes = new byte[16];
byte[] iv_bytes = new byte[16];
getKeyAndGenerateIv(password, random_bytes, key_bytes, iv_bytes);
SecretKey secret = new SecretKeySpec(key_bytes, "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv_bytes);
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}catch(NoSuchPaddingException e) {
throw e;
}catch(NoSuchAlgorithmException e) {
throw e;
}
try {
cipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
}catch(InvalidKeyException e) {
throw e;
}catch(InvalidAlgorithmParameterException e) {
throw e;
}
byte[] encrypted_bytes;
try {
encrypted_bytes = cipher.doFinal(plaintext.getBytes(charset));
}catch(IllegalBlockSizeException e) {
throw e;
}catch(BadPaddingException e) {
throw e;
}
final String header_string = "Salted__";
byte[] header_bytes = header_string.getBytes(charset);
int length = header_bytes.length + random_bytes.length + encrypted_bytes.length;
ByteBuffer byte_buffer = ByteBuffer.allocate(length);
byte_buffer.put(header_bytes);
byte_buffer.put(random_bytes);
byte_buffer.put(encrypted_bytes);
byte_buffer.rewind();
byte[] byte_array = new byte[length];
byte_buffer.get(byte_array);
return new String(Base64.encodeBase64(byte_array));
//Pour Java 8 ou version ultérieure, il peut être décrit comme suit.
//return new String(Base64.getEncoder().encodeToString(byte_array));
}
private String decrypt(String payload, String password) throws Throwable{
byte[] payload_bytes = Base64.decodeBase64(payload.getBytes(charset));
//Pour Java 8 ou version ultérieure, il peut être décrit comme suit.
//byte[] payload_bytes = Base64.getDecoder().decode(payload.getBytes(StandardCharsets.UTF_8));
byte[] header_bytes = new byte[8];
byte[] salt_bytes = new byte[8];
int length = payload_bytes.length;
ByteBuffer byte_buffer = ByteBuffer.allocate(length);
byte_buffer.put(payload_bytes);
byte_buffer.rewind();
byte_buffer.get(header_bytes);
byte_buffer.get(salt_bytes);
length = payload_bytes.length - header_bytes.length - salt_bytes.length;
byte[] data_bytes = new byte[length];
byte_buffer.get(data_bytes);
byte[] key_byte = new byte[16];
byte[] iv_bytes = new byte[16];
getKeyAndGenerateIv(password, salt_bytes, key_byte, iv_bytes);
SecretKey secret = new SecretKeySpec(key_byte, "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv_bytes);
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}catch(NoSuchPaddingException e) {
throw e;
}catch(NoSuchAlgorithmException e) {
throw e;
}
try {
cipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
}catch(InvalidKeyException e) {
throw e;
}catch(InvalidAlgorithmParameterException e) {
throw e;
}
byte[] decrypted;
try {
decrypted = cipher.doFinal(data_bytes);
}catch(IllegalBlockSizeException e) {
throw e;
}catch(BadPaddingException e) {
throw e;
}
return new String(decrypted);
}
}
EncDecTest
import java.io.InputStream;
import javax.xml.bind.JAXB;
public class EncDecTest {
public static void main(String[] args) {
EncDecTest t = new EncDecTest();
t.execute();
}
public void execute() {
InputStream is = this.getClass().getClassLoader().getResourceAsStream("property.xml");
PropertyBean prop = JAXB.unmarshal(is, PropertyBean.class);
EncDecConverter<PropertyBean> c = new EncDecConverter<PropertyBean>(prop,"yakisoba","UTF-8");
if(!c.decrypt()) {
System.err.println("error.");
System.exit(1);
}
System.out.println(prop.getXxUser()); //Sortie hogeyama
System.out.println(prop.getXxPass()); //Sortie du mot de passe hogeyamano
System.out.println(prop.getMiscItem1()); //Sortie hoge
System.out.println(prop.getMiscItem2()); //Sortie fuga
System.exit(0);
}
}
Si le résultat de la méthode de déchiffrement est vrai Dans l'instance PropertyBean passée en argument ** Le champ à déchiffrer ** a été déchiffré. Tout ce que vous avez à faire est de le récupérer dans le haricot et de l'utiliser normalement.
Comme mentionné ci-dessus, en tant qu'argument du constructeur EncDecConverter Vous devez transmettre le mot de passe principal en texte brut, Dans un premier temps, ** Comment gérer le mot de passe principal et comment effectuer l'I / F? ** ** Ne sera pas mentionné dans cet article.
Je pense qu'il existe également un modèle dans lequel les chaînes de caractères cryptées OpenSSL sont partiellement utilisées au lieu de "texte entier". (Mis à part si c'est la bonne réponse) J'ai donc essayé de résumer ces conseils. De plus, je ne pense pas qu'il soit bon d'utiliser mal la réflexion, mais je l'utilise parce que c'est pratique.
Recommended Posts