2017-05-04 19 views
3

當我創建了加密輸出到一個log4j的日誌文件RollingFileAppender進行使用。 目前它使用AES/ECB/NoPadding,它工作正常。什麼算法創建加密Log4j追加

下面是我們如何創建密碼

public static Cipher getCipher(boolean encrypt) throws Exception { 
    //https://en.wikipedia.org/wiki/Stream_cipher  
    byte[] key = ("sometestkey").getBytes("UTF-8"); 
    MessageDigest sha = MessageDigest.getInstance("SHA-1"); 
    key = sha.digest(key); 
    key = Arrays.copyOf(key, 16); // use only first 128 bit 

    Key k = new SecretKeySpec(key,"AES"); 
    Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding"); 
    if (encrypt) { 
     cipher.init(Cipher.ENCRYPT_MODE, k); 
    } else { 
     cipher.init(Cipher.DECRYPT_MODE, k); 
    } 
    return cipher; 
} 

下面是我們如何創建附加器:

public class EncryptingRollingFileAppender extends RollingFileAppender { 
    private CipherOutputStream s; 
    private Cipher cipher; 
    public EncryptingRollingFileAppender() {super();} 
    public EncryptingRollingFileAppender(Layout layout, String filename, boolean append) throws IOException {super(layout, filename, append);} 
    public EncryptingRollingFileAppender(Layout layout, String filename) throws IOException {super(layout, filename);} 

    @Override 
    protected OutputStreamWriter createWriter(OutputStream outputStream) { 
     if (cipher==null) { 
      try { 
       cipher = DecryptionTools.getCipher(true); 
       s = new CipherOutputStream(outputStream, cipher); 
      } catch (Throwable t) { 
       throw new RuntimeException("failed to initialise encrypting file appender",t); 
      } 
     } 
     OutputStreamWriter out = super.createWriter(s); 
     return out; 
    } 
} 

我們可以通過使用

getCipher(假)解密文件

創建一個適當的解密流。

的問題是,我們的安全團隊正在討價還價約密鑰管理。 他們不喜歡使用對稱密鑰加密,並希望我們使用密鑰對而不是我們必須以某種方式管理的簡單密碼。

有誰知道非填充ECB加密技術會使用密鑰對,並且適合這種流加密和解密?

+0

您可以使用[混合加密](https://en.wikipedia。org/wiki/Hybrid_cryptosystem)與任何非對稱和對稱加密算法的組合,但您還有其他問題。加密的消息需要某種標題。你如何區分同一個日誌文件中的多條消息? –

+0

你正在寫一個配置文件?真? – EJP

+0

@ ArtjomB。你有沒有Java中的混合加密的例子。更具體地說,我可以讓RC4使用異步密鑰對嗎? – Richard

回答

0

使用混合加密和PGP暗示的意見是正確的。
PGP是文件混合加密的實際標準,它是ECB模式AES更強大的解決方案。

由於PGP的性質,它將會略有不同工作,以現有的解決方案。

PGP消息有一個頭和頁腳,所以你會希望每個文件進行單獨加密(你不會只能夠解密各個塊像您可以用普通ECB模式加密)。

看起來你正在使用log4j的1.2,I have created a working implementation of a PGP encrypting RollingFileAppender.

要使用示例,生成裝甲編碼的PGP公鑰,運行主類,然後解密任何PGP工具的文件(我用的GnuPG用於創建密鑰和解密)。

的例子建對log4j:log4j:1.2.17org.bouncycastle:bcpg-jdk15on:1.56

+0

謝謝你,太棒了。 我不認爲我可以使用PGP,因爲它不允許我們解密正在寫入的文件。此外,PGP之後的文件大小遠大於未加密的文件。 我想我需要的是一種使用某種巧妙的密鑰對系統的RC4的方式。經過大量的研究,我不相信這是可能的。 相反,我已經解決了使用一個簡單的密碼來將密鑰轉換成其他東西。該加密密鑰隨後用於加密和解密日誌。然後我只是混淆了jar來隱藏加密。這是不安全的,但它是向前邁進的一步 – Richard

+0

如果禁用ascii「Armor」編碼,文件的大小應該大致相同(文件大小增加時,文件頭有一些固定大小的開銷變得毫無意義, bouncycastle也有壓縮選項)。在編寫文件時應該在技術上解密文件,但標準工具可能不會工作,但可以編寫一些代碼來完成它。我會避免RC4,如果你真的想要一個流密碼,你可以在CFB模式下使用AES,那麼現在真的沒有理由使用它。 – Magnus

+0

但是aes是對稱密鑰,所以我仍然有隱藏密鑰的問題。 – Richard

0

您是非常接近你想要達到的目標。使用Log4j 1.2(因爲您無法直接在Log4j 2中繼承RollingFileAppender),您可以爲每個日誌文件實時生成密碼,使用RSA加密密碼並將其存儲在其旁邊。然後使用密碼爲日誌appender生成AES CipherOutputStream。

public class EncryptingRollingFileAppender extends RollingFileAppender { 

    private CipherOutputStream s; 

    private Cipher cipher; 

    private byte[] secretKey; 

    public EncryptingRollingFileAppender(Layout layout, String filename, boolean append) throws IOException { 
     super(layout, filename, append); 
     writeKeyFile(filename); 
    } 

    public EncryptingRollingFileAppender(Layout layout, String filename) throws IOException { 
     super(layout, filename); 
     writeKeyFile(filename); 
    } 

    private void writeKeyFile(final String logfilename) throws IOException { 
     final int dot = logfilename.lastIndexOf('.'); 
     final String keyfilename = (dot == -1 ? logfilename : logfilename.substring(0, dot)) + ".key"; 
     try (FileOutputStream out = new FileOutputStream(keyfilename)) { 
      out.write(DecryptionTools.encryptPasswordBase64(secretKey).getBytes(ISO_8859_1)); 
     } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | KeyStoreException 
       | CertificateException e) { 
     } 
    } 

    @Override 
    protected OutputStreamWriter createWriter(OutputStream outputStream) { 
     System.out.println("createWriter()"); 
     if (cipher == null) { 
      secretKey = DecryptionTools.generateRandomKey(16).getBytes(ISO_8859_1); 
      try { 
       cipher = DecryptionTools.getCipher(true, secretKey); 
      } catch (InvalidKeyException e) { 
       System.out.println("InvalidKeyException"); 
      } 
      s = new CipherOutputStream(outputStream, cipher); 
     } 

     OutputStreamWriter out = super.createWriter(s); 
     return out; 
    } 
} 

You'll需要幾個輔助函數用於讀取文件或從中可以發現here一個Java密鑰存儲私鑰。

測試文件TestEncryptingRollingFileAppender展示瞭如何編寫一個加密的日誌和讀回。

import static com.acme.DecryptionTools.getCipher; 
import static com.acme.DecryptionTools.decryptPasswordBase64; 

public class TestEncryptingRollingFileAppender { 

    @SuppressWarnings("deprecation") 
    @Test 
    public void testAppender() throws IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, KeyStoreException, CertificateException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException { 

     final File logfile = File.createTempFile("testlog_", ".log"); 
     final String logfilename = logfile.getAbsolutePath(); 

     final Logger lggr = LogManager.getLogger(TestEncryptingRollingFileAppender.class); 
     final EncryptingRollingFileAppender appender = new EncryptingRollingFileAppender(new SimpleLayout(), logfilename, true); 

     appender.append(new LoggingEvent(lggr.getClass().getName(), lggr, Priority.INFO, "Test Log Line #1", null)); 
     appender.append(new LoggingEvent(lggr.getClass().getName(), lggr, Priority.INFO, "Test Log Line #1", null)); 

     final int dot = logfilename.lastIndexOf('.'); 
     byte[] key = decryptPasswordBase64(new String(Files.readAllBytes(Paths.get(logfilename.substring(0, dot)+".key")))); 

     StringBuilder logContent = new StringBuilder(); 
     try (FileInputStream instrm = new FileInputStream(logfilename); 
      CipherInputStream cistrm = new CipherInputStream(instrm, getCipher(false, key))) { 
      int c; 
      while ((c=cistrm.read())!=-1) 
       logContent.append((char) c); 
     } 

     assertEquals("INFO - Test Log Line #1\r\nINFO - Test Log Line #1", logContent.toString()); 

    } 
}