在Java中加密文本文件的最简单方法

13

为了展示我能在程序中使用文件处理,我为我的学校项目制作了一个非常简单的登录流程,你可以创建一个账户,并将用户名和密码写入到位于资源文件夹中的文本文件中。显然,这完全没有安全性,因为它并不是为了展示文件处理而设计的,但我的老师说我应该尝试为文件添加一些加密以获得更好的成绩。

我已经做了一些研究,很多人推荐使用 DES。

问题在于我没有太多时间来完成我的项目,需要尽快完成。使用DES似乎需要实现所有额外的代码,这需要花费很长时间。

在我的程序中,我正在使用一个简单的 lineNumberReader 按行读取文件。要写入文件,我正在使用 BufferedWriter。

有没有办法非常简单地加密这些数据? 它不必非常安全,但我需要展示我至少尝试过加密数据。 加密和解密都将在同一个应用程序中完成,因为数据没有被传输。

也许有一种方法可以自己创建非常简单的加密和解密算法吗?


1
如果我要评分的话,我更喜欢学生找出如何使用现有的JDK加密功能(例如AES)。API有点冗长,但您可以在此网站上找到示例代码。像这样的:https://dev59.com/GHrZa4cB1Zd3GeqP5as0#20796446 - Thilo
一个很好的起点可能是Java密码体系结构指南。 - SubOptimal
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Aris2World
1
http://www.ecestudents.ul.ie/Course_Pages/Btech_ITT/Modules/ET4263/More%20Samples/CEncrypt.java.html - StanislavL
11个回答

29

试试这个,它相当简单。

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class HelloWorld{
    public static void main(String[] args) {

        try{
            KeyGenerator keygenerator = KeyGenerator.getInstance("DES");
            SecretKey myDesKey = keygenerator.generateKey();

            Cipher desCipher;
            desCipher = Cipher.getInstance("DES");


            byte[] text = "No body can see me.".getBytes("UTF8");


            desCipher.init(Cipher.ENCRYPT_MODE, myDesKey);
            byte[] textEncrypted = desCipher.doFinal(text);

            String s = new String(textEncrypted);
            System.out.println(s);

            desCipher.init(Cipher.DECRYPT_MODE, myDesKey);
            byte[] textDecrypted = desCipher.doFinal(textEncrypted);

            s = new String(textDecrypted);
            System.out.println(s);
        }catch(Exception e)
        {
            System.out.println("Exception");
        }
    }
}

基本上,在写入文件之前,您需要进行加密,读取后需要解密。


4
必须使用特定的编码(如“UTF-8”)来调用 getBytes() 方法。否则,如果在不同的机器上对其进行解密,并使用不同的系统编码,则无法正确解密。 - Artjom B.
1
是的,任何可以使您的代码更清晰和模块化的东西,都要去做...d(-_^)good!! - j4rey
你应该指定操作模式而不仅仅是块密码。 - CodesInChaos
3
每次运行它,这难道不会生成一个新的密钥吗?另外它是否没有提供任何保存该密钥的方式? - ifly6
1
DES已不再被认为是安全的,请改用AES - Captain Man
显示剩余2条评论

3

一个非常基本的方法是使用密钥对数据进行异或运算。这种方法是对称的,也就是说你可以使用相同的密钥来解码和编码。

如果我们选择一个1字节的密钥,那么它足够简单,足以使其难以阅读(但并不安全!):

private void encodeDecode(byte[] bytes, byte key) {
    for(int i=0; i<bytes.length; i++)
        bytes[i] = (byte) (bytes[i]^key);
}

3
一个简单有趣的混淆算法是Burrows-Wheeler transform。虽然不是一种安全的加密方式,但这只是一项学校作业而已,非常棒。

3

使用简单的替换加密算法,将每个字符替换为数字或其他字符。

  1. 获取您字符串的每个字符。
  2. 获取字符串的ascii值。
  3. 将ascii值加上特定整数(这将是您的加密密钥)。
  4. 显示结果。

1
更好的方法是对它们进行复杂的数学运算 :P - rassa45

2

您可以使用简单的凯撒密码进行加密(http://en.wikipedia.org/wiki/Caesar_cipher

public class Cipher {
public static void main(String[] args) {

    String str = "The quick brown fox Jumped over the lazy Dog";

    System.out.println( Cipher.encode( str, 12 ));
    System.out.println( Cipher.decode( Cipher.encode( str, 12), 12 ));
}

public static String decode(String enc, int offset) {
    return encode(enc, 26-offset);
}

public static String encode(String enc, int offset) {
    offset = offset % 26 + 26;
    StringBuilder encoded = new StringBuilder();
    for (char i : enc.toCharArray()) {
        if (Character.isLetter(i)) {
            if (Character.isUpperCase(i)) {
                encoded.append((char) ('A' + (i - 'A' + offset) % 26 ));
            } else {
                encoded.append((char) ('a' + (i - 'a' + offset) % 26 ));
            }
        } else {
            encoded.append(i);
        }
    }
    return encoded.toString();
}
}

发现于http://rosettacode.org/wiki/Caesar_cipher#Java

请注意,Java有本地解决方案用于加密,当涉及密码时,最好只需对其进行哈希处理并比较哈希值,因为通常不需要解密它们。


1
这是一个很酷的东西,但是太容易出问题了。不建议使用。 - Tanner Summers

1
Bouncy Castle Crypto API 是一个轻量级的 Java 加密 API。
    import org.bouncycastle.crypto.*;
    import org.bouncycastle.crypto.engines.*;
    import org.bouncycastle.crypto.modes.*;
    import org.bouncycastle.crypto.params.*;

    // A simple example that uses the Bouncy Castle
    // lightweight cryptography API to perform DES
    // encryption of arbitrary data.


     public class Encryptor {

            private BufferedBlockCipher cipher;
            private KeyParameter key;


            // Initialize the cryptographic engine.
            // The key array should be at least 8 bytes long.


            public Encryptor( byte[] key ){
            /*
            cipher = new PaddedBlockCipher(
                       new CBCBlockCipher(new DESEngine()));
            */
            cipher = new PaddedBlockCipher(
                        new CBCBlockCipher(new BlowfishEngine()));
            this.key = new KeyParameter( key );
            }        

            // Initialize the cryptographic engine.
            // The string should be at least 8 chars long.

            public Encryptor( String key ){
            this( key.getBytes());
            }
            // Private routine that does the gritty work.

            private byte[] callCipher( byte[] data )
            throws CryptoException {
            int    size = cipher.getOutputSize( data.length );

            byte[] result = new byte[ size ];
            int    olen = cipher.processBytes(data,0,data.length result, 0);
                   olen += cipher.doFinal( result, olen );

            if( olen < size ){
                byte[] tmp = new byte[ olen ];
                System.arraycopy(
                        result, 0, tmp, 0, olen );
                result = tmp;
            }

            return result;
        }
        // Encrypt arbitrary byte array, returning the
        // encrypted data in a different byte array.

        public synchronized byte[] encrypt( byte[] data )
        throws CryptoException {
            if( data == null || data.length == 0 ){
                return new byte[0];
            }

            cipher.init( true, key );
            return callCipher( data );
        }
       // Encrypts a string.

        public byte[] encryptString( String data )
        throws CryptoException {
            if( data == null || data.length() == 0 ){
                return new byte[0];
            }

            return encrypt( data.getBytes() );
        }
        // Decrypts arbitrary data.

        public synchronized byte[] decrypt( byte[] data )
        throws CryptoException {
            if( data == null || data.length == 0 ){
                return new byte[0];
            }

            cipher.init( false, key );
            return callCipher( data );
        }
        // Decrypts a string that was previously encoded
        // using encryptString.

        public String decryptString( byte[] data )
        throws CryptoException {
            if( data == null || data.length == 0 ){
                return "";
            }

            return new String( decrypt( data ) );
        }
    }

1
我不知道是谁推荐使用DES加密密码。 如果您想给您的老师留下深刻印象,我建议您按照以下步骤操作:

这个解决方案可以让您的项目变得更实际,并且您可以重复使用它来通过未来的Crypto Module考试 :)。否则,我喜欢StanislavL提出的解决方案。

享受吧!


0

在Java中,有太多加密简单字符串的方法。如果这是一个学校项目,我真的不认为你可以通过简单地使用一些第三方库来完成加密工作而获得更高的分数。

如果你有时间,可以尝试了解Base64的工作原理,然后尝试自己创建一些加密算法。

然而,如果你坚持要使用Java中的某些API,我必须说DES是一种非常老旧的加密方式,3DES(DESede)或AES会更好、更安全,它们都已经被Java6支持。

如果你必须导入BouncyCastle库,我推荐使用IDEA,它是最安全的算法之一,可能会让你获得一个好成绩。

我不会给你任何演示代码,但你可以很容易地通过谷歌搜索我提到的所有算法来找到一些。


-3
public class CryptoUtils {

    public static void encrypt(String key, File inputFile, File outputFile)
            throws CryptoException {
        doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
    }

    public static void decrypt(String key, File inputFile, File outputFile)
            throws CryptoException {
        doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
    }

    private static void doCrypto(int cipherMode, String key, File inputFile,
            File outputFile) throws CryptoException {
        try {
            Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(cipherMode, secretKey);

            FileInputStream inputStream = new FileInputStream(inputFile);
            byte[] inputBytes = new byte[(int) inputFile.length()];
            inputStream.read(inputBytes);

            byte[] outputBytes = cipher.doFinal(inputBytes);

            FileOutputStream outputStream = new FileOutputStream(outputFile);
            outputStream.write(outputBytes);

            inputStream.close();
            outputStream.close();

        } catch (NoSuchPaddingException | NoSuchAlgorithmException
                | InvalidKeyException | BadPaddingException
                | IllegalBlockSizeException | IOException ex) {
            throw new CryptoException("Error encrypting/decrypting file", ex);
        }
    }
}

package net.codejava.crypto;

import java.io.File;

public class CryptoException extends Exception {

    public CryptoException() {
    }

    public CryptoException(String message, Throwable throwable) {
        super(message, throwable);
    }

    public static void main(String[] args) {
        String key = "Mary has one cat1";
        File inputFile = new File("document.txt");
        File encryptedFile = new File("document.encrypted");
        File decryptedFile = new File("document.decrypted");

        try {
            CryptoUtils.encrypt(key, inputFile, encryptedFile);
            CryptoUtils.decrypt(key, encryptedFile, decryptedFile);
        } catch (CryptoException ex) {
            System.out.println(ex.getMessage());
            ex.printStackTrace();
        }
    }
}

欢迎来到Stack Overflow!感谢您提供这段代码片段,它可能会提供一些有限的、即时的帮助。通过展示为什么这是一个好的解决方案,适当的解释将极大地提高其长期价值,并使其对未来有其他类似问题的读者更有用。请编辑您的答案,添加一些解释,包括您所做的假设。 - Toby Speight

-4
我的建议:根本不要使用加密。 这里有更好的方案:(希望如此)
Scanner sc=new Scanner(System.in);
String name=sc.next();
//for inputting user name
File f= new File("d://"+name+".txt");
if(f.exists())
{
if(f.lastModified()!=0)
{ 
System.out.println("Account data tampered...cannot be accessed"); 
}
else{
String data="";
System.out.println(data); //data should contain 
//data from file read using BufferedReader
f.setLastModified(0);
}
}
else
{
f.createNewFile();//Write whatever you want to to the file 
f.setLastModified(0);
}

因此,您可以有效地知道用户是否篡改了包含详细信息的文本文件,并在使用被篡改的帐户时显示错误消息。 但是,这并不能防止用户更改文件,它只能防止使用被篡改的帐户......我认为你的计算机老师可能会喜欢这个。 您还可以执行以下操作: f.setReadOnly(); 并且当您写入文件时, f.setWritable(true,true), 然后在关闭输出流之后, f.setReadOnly(); 再次... 但是文件仍然可以被替换,因此第一个选项更加有效。 谢谢


4
这没什么意义。文件中只有用户名和密码。既然可以从文件中读取用户名/密码,为什么还需要改变文件呢? - JJJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接