java实现消息认证码签名与验证

java实现消息认证码签名与验证:想改进一下实验代码,要签名的对象为参数dataSetFolder路径中的每个文件的内容(每个文件都为英文电子邮件)、参数positionMap和一个随循环次数自增的参数fileCounter。每次循环都生成一个MAC签名,并验证签名内容的正确性,如正确则系统输出Accept,并把MAC签名写成一个txt格式的文件保存在本地且txt文件命名为自增的数字序号。

部分代码如图:

img

程序代码如下:

import client.utils.*;
import it.unisa.dia.gas.jpbc.Element;
import orestes.bloomfilter.CountingBloomFilter;
import orestes.bloomfilter.FilterBuilder;
import pojo.PrivateKey;
import pojo.PublicKey;
import server.Search;
import server.utils.HomoEncryption_Server;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;


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

        KeyGenUtils.genKey();
        Object[] key = KeyGenUtils.getKeyFromFile("key.data");

        PublicKey publicKey = (PublicKey) key[0];
        PrivateKey privateKey = (PrivateKey) key[1];


        CountingBloomFilter<Object> cbf = new FilterBuilder(1000000, 0.01)
                .buildCountingBloomFilter();
        ConcurrentHashMap<Integer, HashMap<String, ArrayList<Element>>> filesMaps = new ConcurrentHashMap<>();

        File dataSetFolder = new File("C:\\mypaperdataset\\enron\\version2\\10000");

        ExecutorService executorService = Executors.newCachedThreadPool();

        long s = System.currentTimeMillis();
        AtomicInteger fileCounter = new AtomicInteger(1);

        for (File file : dataSetFolder.listFiles()) {
//            if (count==7000) break;
//            count++;
            Integer node = NodeGen_Client.getNode();

            executorService.execute(()->{
                System.out.println("正在处理文件:" + file.getName() +"分配的节点:"+node);
                List<String> extracted = ExtractKeyword.extract_easy(file);//一个文件提取关键词耗费5ms
                IndexBuilding.buildCBF_Batch(extracted, node, cbf);
                HashMap<String, ArrayList<Element>> positionMap = IndexBuilding.buildHashTable_exp(extracted, privateKey);
                filesMaps.put(node, positionMap);
            });
        }


        executorService.shutdown();


        try {
            while (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
                System.out.println("线程池没有关闭");
//                System.out.println("isTerminated:" + executorService.isTerminated());
                ThreadPoolExecutor executor = (ThreadPoolExecutor) executorService;
                System.out.println("剩余线程数: "+executor.getActiveCount());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long e = System.currentTimeMillis();

        System.out.println("线程池已经关闭");
        System.out.println("isTerminated:" + executorService.isTerminated());
        System.out.println("用时:"+(e-s)+"毫秒");

        // 搜索
        HomoEncryption_Client homo_client = new HomoEncryption_Client(privateKey, publicKey);
        Element elementX = homo_client.getElementX();
        Element elementY = homo_client.getElementY();


        while (true) {
            ArrayList<String> keywords = new ArrayList<>();
            while (true) {
                System.out.println("请输入:");
                Scanner input = new Scanner(System.in);
                String next = input.next();
                if (next.equals("0")) {
                    System.out.println("开始查询");
                    break;
                }
                keywords.add(MyHashUtils.md5(next));
            }


            HomoEncryption_Server homo_server = new HomoEncryption_Server(publicKey);



            long kk = System.nanoTime();
            List<Integer> search_result1 = Search.searchKeywords(keywords, cbf);
            long ll = System.nanoTime();
            System.out.println("普通查询完成,用时:"+(ll-kk)+"ns 查询到了"+search_result1.size()+"个文件");

            long pp = System.nanoTime();
            List<Integer> search_result2 = Search.searchKeywords_Phrase(keywords, cbf, filesMaps, homo_server, elementX, elementY);
            long jj = System.nanoTime();
            System.out.println("词组查询完成,用时:"+(jj-pp)+"ms 查询到了"+search_result2.size()+"个文件");




        }

    }
}


以下是修改后的代码,根据你的要求添加了MAC签名的功能:

import client.utils.*;
import it.unisa.dia.gas.jpbc.Element;
import orestes.bloomfilter.CountingBloomFilter;
import orestes.bloomfilter.FilterBuilder;
import pojo.PrivateKey;
import pojo.PublicKey;
import server.Search;
import server.utils.HomoEncryption_Server;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class Phrase_multi {
    private static final String MAC_ALGORITHM = "HmacSHA256";

    public static void main(String[] args) {
        KeyGenUtils.genKey();
        Object[] key = KeyGenUtils.getKeyFromFile("key.data");

        PublicKey publicKey = (PublicKey) key[0];
        PrivateKey privateKey = (PrivateKey) key[1];

        CountingBloomFilter<Object> cbf = new FilterBuilder(1000000, 0.01)
                .buildCountingBloomFilter();
        ConcurrentHashMap<Integer, HashMap<String, ArrayList<Element>>> filesMaps = new ConcurrentHashMap<>();

        File dataSetFolder = new File("C:\\mypaperdataset\\enron\\version2\\10000");

        ExecutorService executorService = Executors.newCachedThreadPool();

        long s = System.currentTimeMillis();
        AtomicInteger fileCounter = new AtomicInteger(1);

        for (File file : dataSetFolder.listFiles()) {
            Integer node = NodeGen_Client.getNode();

            executorService.execute(() -> {
                System.out.println("正在处理文件:" + file.getName() + " 分配的节点:" + node);
                List<String> extracted = ExtractKeyword.extract_easy(file);
                IndexBuilding.buildCBF_Batch(extracted, node, cbf);
                HashMap<String, ArrayList<Element>> positionMap = IndexBuilding.buildHashTable_exp(extracted, privateKey);
                filesMaps.put(node, positionMap);

                // Generate and verify MAC signature
                String macSignature = generateMacSignature(file.getAbsolutePath(), positionMap, fileCounter.getAndIncrement());
                if (verifyMacSignature(file.getAbsolutePath(), macSignature, positionMap, fileCounter.get() - 1)) {
                    System.out.println("Accept");
                    saveMacSignatureToFile(fileCounter.get() - 1, macSignature);
                }
            });
        }

        executorService.shutdown();

        try {
            while (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
                System.out.println("线程池没有关闭");
                ThreadPoolExecutor executor = (ThreadPoolExecutor) executorService;
                System.out.println("剩余线程数: " + executor.getActiveCount());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long e = System.currentTimeMillis();

        System.out.println("线程池已经关闭");
        System.out.println("isTerminated: " + executorService.isTerminated());
        System.out.println("用时: " + (e - s) + "毫秒");

        // 搜索
        HomoEncryption_Client homo_client = new HomoEncryption_Client(privateKey, publicKey);
        Element elementX = homo_client.getElementX();
        Element elementY = homo_client.getElementY();

        while (true) {
            ArrayList<String> keywords = new ArrayList<>();
            while (true) {
                System.out.println("请输入:");
                Scanner input = new Scanner(System.in);
                String next = input.next();
                if (next.equals("0")) {
                    System.out.println("开始查询");
                    break;
                }
                keywords.add(MyHashUtils.md5(next));
            }

            HomoEncryption_Server homo_server = new HomoEncryption_Server(publicKey);

            long kk = System.nanoTime();
            List<Integer> search_result1 = Search.searchKeywords(keywords, cbf);
            long ll = System.nanoTime();
            System.out.println("普通查询完成,用时:" + (ll - kk) + "ns 查询到了" + search_result1.size() + "个文件");

            long pp = System.nanoTime();
            List<Integer> search_result2 = Search.searchKeywords_Phrase(keywords, cbf, filesMaps, homo_server, elementX, elementY);
            long jj = System.nanoTime();
            System.out.println("词组查询完成,用时:" + (jj - pp) + "ms 查询到了" + search_result2.size() + "个文件");
        }
    }

    private static String generateMacSignature(String filePath, HashMap<String, ArrayList<Element>> positionMap, int fileCounter) {
        try {
            String data = readFileAsString(filePath);
            StringBuilder sb = new StringBuilder();
            sb.append(data);

            for (String keyword : positionMap.keySet()) {
                sb.append(keyword);
                for (Element element : positionMap.get(keyword)) {
                    sb.append(element);
                }
            }

            String dataToSign = sb.toString();

            Mac mac = Mac.getInstance(MAC_ALGORITHM);
            SecretKey secretKey = generateMacSecretKey(fileCounter);
            mac.init(secretKey);
            byte[] signatureBytes = mac.doFinal(dataToSign.getBytes());

            return bytesToHexString(signatureBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private static boolean verifyMacSignature(String filePath, String macSignature, HashMap<String, ArrayList<Element>> positionMap, int fileCounter) {
        try {
            String data = readFileAsString(filePath);
            StringBuilder sb = new StringBuilder();
            sb.append(data);

            for (String keyword : positionMap.keySet()) {
                sb.append(keyword);
                for (Element element : positionMap.get(keyword)) {
                    sb.append(element);
                }
            }

            String dataToVerify = sb.toString();

            Mac mac = Mac.getInstance(MAC_ALGORITHM);
            SecretKey secretKey = generateMacSecretKey(fileCounter);
            mac.init(secretKey);
            byte[] signatureBytes = mac.doFinal(dataToVerify.getBytes());
            String generatedSignature = bytesToHexString(signatureBytes);

            return macSignature.equals(generatedSignature);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    private static SecretKey generateMacSecretKey(int fileCounter) {
        try {
            KeyGenerator keyGen = KeyGenerator.getInstance(MAC_ALGORITHM);
            keyGen.init(256); // Adjust key size as needed
            SecretKey secretKey = keyGen.generateKey();
            byte[] encodedKey = secretKey.getEncoded();
            Path keyFilePath = Path.of("mac_keys", fileCounter + ".txt");
            Files.createDirectories(keyFilePath.getParent());
            Files.write(keyFilePath, encodedKey, StandardOpenOption.CREATE);

            return secretKey;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private static String readFileAsString(String filePath) {
        try {
            return new String(Files.readAllBytes(Path.of(filePath)));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    private static void saveMacSignatureToFile(int fileCounter, String macSignature) {
        try {
            String fileName = fileCounter + ".txt";
            FileWriter writer = new FileWriter(fileName);
            writer.write(macSignature);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}

这个修改后的代码添加了以下功能:

在循环处理每个文件时生成MAC签名,并验证签名的正确性。
如果签名验证通过,将MAC签名保存到本地以自增的数字序号作为文件名的txt文件中。
请确保在运行代码之前创建名为mac_keys的文件夹,用于保存生成的MAC密钥。

注意:该代码只提供了基本的MAC签名功能,但并未包含数据完整性和安全性的全面保护。

你是想改什么?

  • 以下回答由chatgpt基于相关博客总结生成:

    问题回答:

    实现消息认证码的签名和验证可以使用Java提供的加密技术,具体来说,可以使用Java加密标准(JCE)提供的加密库,如增强型加密标准(AES)、数据加密标准(DES)等等。

    下面是实现消息认证码的签名和验证的大体思路:

    1. 使用密钥生成MessageDigest(消息摘要)对象,用于生成消息摘要。
    2. 消息内容进行摘要操作。
    3. 使用密钥进行加密操作。
    4. 签名结果同时包含式样,使接收方得到签名的同时,同时得到摘要和密文。
    5. 接收方计算收到消息的摘要,用密钥进行解密操作,检查解密结果是不是和摘要一样。

    下面是一个简单的示例代码,用于对消息进行签名和验证:

    import java.security.*;
    
    public class MessageAuthenticationCode {
        private static final String HMAC_SHA512 = "HmacSHA512";
    
        public static byte[] createHmac(byte[] key, byte[] data) throws Exception {
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, HMAC_SHA512);
            Mac mac = Mac.getInstance(HMAC_SHA512);
            mac.init(secretKeySpec);
            return mac.doFinal(data);
        }
    
        public static void main(String[] args) throws Exception {
            String message = "this is a sample message";
            byte[] key = "12345678".getBytes();
            byte[] hmac = createHmac(key, message.getBytes());
    
            System.out.println("Message: " + message);
            System.out.println("HMAC: " + new String(hmac));
    
            boolean isValid = checkHmac(key, message.getBytes(), hmac);
            System.out.println("Is valid? " + isValid);
        }
    
        public static boolean checkHmac(byte[] key, byte[] data, byte[] hmac) throws Exception {
            byte[] newData = createHmac(key, data);
            if (newData.length != hmac.length) {
                return false;
            }
    
            for (int i = 0; i < newData.length; i++) {
                if (newData[i] != hmac[i]) {
                    return false;
                }
            }
    
            return true;
        }
    }
    

    在上面的示例代码中,我们使用了Java提供的javax.crypto.Mac类对消息进行签名。对于消息,我们使用了字符串,对于密钥,我们使用了字节数组。如果需要生成更强的密钥,可以使用Java Cryptography Extension(JCE)提供的KeyGenerator类。

    以上是生成签名的代码,如果需要验证签名,则需要将签名和产生签名的消息都传递到接收方,接收方使用相同的方式生成签名,并将两个签名进行比较。如果两个签名相同,则认为消息是真实的。

    总结:Java提供了许多用于加密和签名的库,可以使用这些库轻松地实现消息认证码的签名和验证。