Java加解密(七)数字签名

news2024/11/20 13:36:34

目录

  • 数字签名
    • 1 定义
    • 2 数字签名特点
    • 3 应用场景
    • 4 JDK支持的信息摘要算法
    • 5 Bouncy Castle 支持的信息摘要算法
    • 6 算法调用示例

数字签名

1 定义

数字签名(digital signature)是一种电子签名,也可以表示为一种数学算法,通常用于验证消息(例如,电子邮件、信用卡交易或数字文档)的真实性和完整性。

数字签名并没有创建新的算法,主要是结合使用信息摘要算法(MD,SHA)和非对称加密算法(RSA,DSA)。信息摘要算法用来验证数据完整性,非对称加密算法用来进行身份验证。

消息发送方用摘要算法和私钥加密生成签名,接收方用公钥解密验证签名,再用相同的摘要算法验证数据完整性。

一个典型的消息发送过程如下:

在这里插入图片描述

2 数字签名特点

  • 防篡改:数据不会被修改,MAC算法也有这个特点。
  • 防抵赖:消息签署者不能抵赖。
  • 防伪造:发送的消息不能够伪造,MAC算法也有这个特点。

3 应用场景

数字签名具有许多重要的应用,例如在电子政务活动中的电子公文、网上报税、网上投票,在电子商务活动中的电子订单、电子账单、电子收据、电子合同、电子现金等电子文档都需要通过数字签名来保证文档的真实性和有效性;甚至于人们日常使用频繁的电子邮件,当涉及重要内容时,也需要通过数字签名技术来对邮件的发送者进行确认和保证邮件内容未被篡改,并且邮件的发送者也不能对发出的邮件进行否认。由此可见,数字签名技术早已深入应用到国家的政治、军事、经济和人们生活中的各个方面,并将在国家数字 化进程中发挥越来越重要的作用。

4 JDK支持的信息摘要算法

JDK8原生算法列表,可参第一篇博文: https://blog.csdn.net/yunyun1886358/article/details/128592503#311_JDK_Provider_63

5 Bouncy Castle 支持的信息摘要算法

Bouncy Castle算法列表,可参第一篇博文:
https://editor.csdn.net/md/?articleId=128592503#323_Bouncy_Castle_Provider_568

6 算法调用示例

下面的代码将JDK提供的几种数字签名算法用枚枚举类进行了封装。

package com.qupeng.crypto.algorithm.oop;

import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;

public class DigitalSignatureAlgotithmTest {

    @Test
    public void sign() throws Exception {
        String signatureStr = DigitalSignatureAlgotithm.MD2withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.MD2withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.MD5withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.MD5withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.SHA1withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.SHA1withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.SHA1withDSA.signByPrivateKeyFromFile("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.SHA1withDSA.verifySignatureByPublicKeyFromFile("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.SHA256withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.SHA256withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.SHA224withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.SHA224withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.SHA384withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.SHA384withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.SHA512withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.SHA512withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.RIPEMD128withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.RIPEMD128withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));

        signatureStr = DigitalSignatureAlgotithm.RIPEMD160withRSA.signByPrivateKeyFromKeyStore("1234567890");
        Assert.assertTrue(DigitalSignatureAlgotithm.RIPEMD160withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr));
    }
}
package com.qupeng.crypto.algorithm.oop;

import com.qupeng.crypto.util.CryptoUtils;
import com.qupeng.crypto.util.DigitalCertificationUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.util.Base64;

public enum DigitalSignatureAlgotithm {
    MD2withRSA("MD2withRSA", "RSA", "default"),
    MD5withRSA("MD5withRSA", "RSA", "default"),
    SHA1withRSA("SHA1withRSA", "RSA", "default"),
    SHA1withDSA("SHA1withDSA", "DSA", "default"),
    SHA256withRSA("SHA256withRSA", "RSA", "default"),
    SHA224withRSA("SHA224withRSA", "RSA", "BC"),
    SHA384withRSA("SHA384withRSA", "RSA", "BC"),
    SHA512withRSA("SHA512withRSA", "RSA", "BC"),
    RIPEMD128withRSA("RIPEMD128withRSA", "RSA", "BC"),
    RIPEMD160withRSA("RIPEMD160withRSA", "RSA", "BC");

    private static Path keyStorePath;

    private static Path certificatePath;

    static {
        Security.addProvider(new BouncyCastleProvider());
        try {
            keyStorePath = Paths.get(DigitalSignatureAlgotithm.class.getClassLoader().getResource("testing-keystore.p12").toURI());
            certificatePath = Paths.get(DigitalSignatureAlgotithm.class.getClassLoader().getResource("testing-ca.cer").toURI());
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

    }

    private String algorithm;
    private String encryptionAlgorithm;
    private String providerName;

    DigitalSignatureAlgotithm(String algorithm, String encryptionAlgorithm, String providerName) {
        this.algorithm = algorithm;
        this.encryptionAlgorithm = encryptionAlgorithm;
        this.providerName = providerName;
    }

    public String signByPrivateKeyFromKeyStore(String plainText) throws Exception {
        PrivateKey privateKey = CryptoUtils.getPrivateKeyFromKeyStore(keyStorePath, "testing-keys", "123456", "PKCS12");
        return sign(plainText, privateKey);
    }

    public String signByPrivateKeyFromFile(String plainText) throws Exception {
        String privateKeyStr = CryptoUtils.readPrivateKeyFromFile(this.encryptionAlgorithm);
        PrivateKey privateKey = CryptoUtils.getPrivateKeyByStr(this.encryptionAlgorithm, privateKeyStr);
        return sign(plainText, privateKey);
    }

    public String sign(String plainText, PrivateKey privateKey) throws Exception {
        Signature signature;
        if ("default".equals(providerName)) {
            signature = Signature.getInstance(this.algorithm);
        } else {
            signature = Signature.getInstance(this.algorithm, providerName);
        }

        signature.initSign(privateKey);
        signature.update(plainText.getBytes());
        byte[] signatureBytes = signature.sign();
        String cipherText = Base64.getEncoder().encodeToString(signatureBytes);
        System.out.println(String.format("%s plain text: %s -> digital signature: %s", this.algorithm, plainText, cipherText));
        return cipherText;
    }

    public boolean verifySignatureByPublicKeyFromCA(String plainText, String signatureStr) throws Exception {
        PublicKey publicKey = DigitalCertificationUtils.getPublicKeyFromCA(certificatePath, "X.509");
        return verifySignature(plainText, signatureStr, publicKey);
    }

    public boolean verifySignatureByPublicKeyFromFile(String plainText, String signatureStr) throws Exception {
        String publicKeyStr = CryptoUtils.readPublicKeyFromFile(this.encryptionAlgorithm);
        PublicKey publicKey = CryptoUtils.getPublicKeyByStr(this.encryptionAlgorithm, publicKeyStr);
        return verifySignature(plainText, signatureStr, publicKey);
    }

    public boolean verifySignature(String plainText, String signatureStr, PublicKey publicKey) throws Exception {
        Signature signature;
        if ("default".equals(providerName)) {
            signature = Signature.getInstance(this.algorithm);
        } else {
            signature = Signature.getInstance(this.algorithm, providerName);
        }

        signature.initVerify(publicKey);
        signature.update(plainText.getBytes());
        boolean verifyResult = signature.verify(Base64.getDecoder().decode(signatureStr));
        System.out.println(String.format("Signature: %s is %s", signatureStr, verifyResult ? "valid" : "invalid"));
        return verifyResult;
    }
}
package com.qupeng.crypto.util;

import com.qupeng.crypto.algorithm.oop.NumberGenerationAlgorithm;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.stream.Collectors;

public class CryptoUtils {

    public final static Path RSA_PUBLIC_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "rsa-public-key.txt");

    public final static Path RSA_PRIVATE_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "rsa-private-key.txt");

    public final static Path DSA_PUBLIC_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "dsa-public-key.txt");

    public final static Path DSA_PRIVATE_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "dsa-private-key.txt");

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void printAllSecurityProviders() {
        for (Provider provider : Security.getProviders())
        {
            System.out.println("Provider: " + provider.getName() + " (ver " + provider.getVersion() + ")");
        }
    }

    public static void printAllAlgorithmsOfProviders() {
        for (Provider provider : Security.getProviders())
        {
            System.out.println("Provider: " + provider.getName() + " (ver " + provider.getVersion() + ")");
            System.out.print("  Algorithms: ");
            ArrayList<String> algos = new ArrayList<String>();
            for (Provider.Service service : provider.getServices())
            {
                algos.add(String.format( "%s (%s)", service.getAlgorithm(), service.getType()));
            }
            java.util.Collections.sort(algos);
            String algorsStr = algos.toString();
            algorsStr = algorsStr.substring(1, algorsStr.length()-1);
            System.out.println(algorsStr);
            System.out.println();
        }
    }

    public static String printAllSecurityProvidersInMdTable() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("Provider Name|Provider Version|Algorithm Type|Algorithm Name\r\n");
        stringBuilder.append("|:-|:-|:-|:-\r\n");
        Map<String, Map<String, String>> providers2Algorithms = Arrays.stream(Security.getProviders())
                .collect(Collectors.toMap(provider -> provider.getName() + "@" + provider.getVersion(), provider -> provider.getServices().stream().collect(Collectors.toMap(service -> service.getType(), service -> service.getAlgorithm(), (algorithm1, algorithm2) -> algorithm1 + "@" + algorithm2))));
        providers2Algorithms.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEachOrdered(entryProvider -> {
            String[] provider = entryProvider.getKey().split("@");
            Map<String, String> algoType2AlgoName = entryProvider.getValue();
            int[] rowNumber = {0};
            algoType2AlgoName.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEachOrdered(entryAlgorithm -> {
                StringBuilder algorithmCellStr = new StringBuilder();
                int[] numberOfAlgorithm = {1};
                Arrays.stream(entryAlgorithm.getValue().split("@")).sorted(String::compareTo).forEachOrdered(algorithm -> {
                    algorithmCellStr.append(algorithm);
                    if (0 == numberOfAlgorithm[0] % 1) {
                        algorithmCellStr.append("<br>");
                    }
                    numberOfAlgorithm[0]++;
                });

                stringBuilder.append(String.format("|%s|%s|%s|%s\r\n", 0 == rowNumber[0] ? provider[0] : "", 0 == rowNumber[0] ? provider[1] : "", entryAlgorithm.getKey(), algorithmCellStr.toString()));
                rowNumber[0]++;
            });
        });

        return stringBuilder.toString();
    }

    public static void writeKeyPairToFile(KeyPair keyPair, String algorithm) throws IOException {
        writeKeyPairToFile(keyPair, "DSA".equalsIgnoreCase(algorithm) ? DSA_PUBLIC_KEY_FILE_PATH : RSA_PUBLIC_KEY_FILE_PATH, "DSA".equalsIgnoreCase(algorithm) ? DSA_PRIVATE_KEY_FILE_PATH : RSA_PRIVATE_KEY_FILE_PATH);
    }

    public static void writeKeyPairToFile(KeyPair keyPair, Path publicKeyFilePath, Path privateKeyFilePath) throws IOException {
        writeKeyToFile(keyPair.getPublic(), publicKeyFilePath);
        writeKeyToFile(keyPair.getPrivate(), privateKeyFilePath);
    }

    public static String readPublicKeyFromFile(String algorithm) throws IOException {
        return readKeyStrFromFile("DSA".equalsIgnoreCase(algorithm) ? DSA_PUBLIC_KEY_FILE_PATH : RSA_PUBLIC_KEY_FILE_PATH);
    }

    public static String readPrivateKeyFromFile(String algorithm) throws IOException {
        return readKeyStrFromFile("DSA".equalsIgnoreCase(algorithm) ? DSA_PRIVATE_KEY_FILE_PATH : RSA_PRIVATE_KEY_FILE_PATH);
    }

    public static String readKeyStrFromFile(Path keyFilePath) throws IOException {
        try (FileChannel keyFileChannel = FileChannel.open(keyFilePath, StandardOpenOption.READ)) {
            byte[] bytes = new byte[0];
            ByteBuffer byteBuffer = ByteBuffer.allocate(128);
            int readCount = keyFileChannel.read(byteBuffer);
            while (0 < readCount) {
                byteBuffer.flip();
                int length = bytes.length;
                bytes = Arrays.copyOf(bytes, bytes.length + readCount);
                System.arraycopy(byteBuffer.array(), 0, bytes, length, readCount);
                byteBuffer.clear();
                readCount = keyFileChannel.read(byteBuffer);
            }
            String keyStr = new String(bytes);
            return keyStr;
        }
    }

    public static void writeKeyToFile(Key key, Path filePath) throws IOException {
        byte[] keyBytes = key.getEncoded();
        String keyStr = new BASE64Encoder().encode(keyBytes);
        if (Files.notExists(filePath)) {
            Files.createFile(filePath);
        }

        try(FileChannel keyFileChannel = FileChannel.open(filePath, StandardOpenOption.WRITE)) {
            ByteBuffer byteBuffer = ByteBuffer.allocate(keyStr.getBytes().length);
            byteBuffer.put(keyStr.getBytes());
            byteBuffer.flip();
            keyFileChannel.write(byteBuffer);
        }
    }

    public static PublicKey getPublicKeyByStr(String algorithm, String secretKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(secretKeyStr);
        X509EncodedKeySpec encPubKeySpec = new X509EncodedKeySpec(keyBytes);
        PublicKey publicKey = KeyFactory.getInstance(algorithm).generatePublic(encPubKeySpec);
        return publicKey;
    }

    public static PrivateKey getPrivateKeyByStr(String algorithm, String secretKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(secretKeyStr);
        PKCS8EncodedKeySpec encPriKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        PrivateKey privateKey = KeyFactory.getInstance(algorithm).generatePrivate(encPriKeySpec);
        return privateKey;
    }

    public static KeyPair getKeyPair(String algorithm, int secretKeyBitLength, String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator  = KeyPairGenerator.getInstance(algorithm);
        SecureRandom random = SecureRandom.getInstance(ngAlgorithm.getAlgorithmName());
        random.setSeed(randomSeedStr.getBytes());
        keyPairGenerator.initialize(secretKeyBitLength, random);
        return keyPairGenerator.generateKeyPair();
    }

    public static String wrapSecretKey(String keyString) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128, new SecureRandom("123456".getBytes()));
        SecretKey secretKey = keyGenerator.generateKey();
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.WRAP_MODE, secretKey);
        SecretKeySpec key = new SecretKeySpec(keyString.getBytes(), "AES");
        byte[] bytes = cipher.wrap(key);
        return Hex.encodeHexString(bytes);
    }

    public static String unwrapSecretKey(String keyString) throws Exception {
        byte[] rawKey = Hex.decodeHex(keyString);
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128, new SecureRandom("123456".getBytes()));
        SecretKey secretKey = keyGenerator.generateKey();
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.UNWRAP_MODE, secretKey);
        SecretKey key = (SecretKey) cipher.unwrap(rawKey, "AES", Cipher.SECRET_KEY);
        return new String(key.getEncoded());
    }

    public static String wrapPrivateKey() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException {
        SecureRandom secureRandom = SecureRandom.getInstance(NumberGenerationAlgorithm.SHA1_PRNG.getAlgorithmName());
        secureRandom.setSeed("12345".getBytes());

        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128, secureRandom);
        SecretKey secretKey = keyGenerator.generateKey();

        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.WRAP_MODE, secretKey, secureRandom);

        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024, secureRandom);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        System.out.println(Hex.encodeHexString(keyPair.getPrivate().getEncoded()));
        byte[] keyBytes = cipher.wrap(keyPair.getPrivate());
        String wrappedKeyStr = Hex.encodeHexString(keyBytes);
        System.out.println(wrappedKeyStr);
        return wrappedKeyStr;
    }

    public static String unwrapPrivateKey(String keyStr) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, DecoderException {
        SecureRandom secureRandom = SecureRandom.getInstance(NumberGenerationAlgorithm.SHA1_PRNG.getAlgorithmName());
        secureRandom.setSeed("12345".getBytes());

        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128, secureRandom);
        SecretKey secretKey = keyGenerator.generateKey();

        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.UNWRAP_MODE, secretKey, secureRandom);

        byte[] keyBytes = Hex.decodeHex(keyStr);
        PrivateKey privateKey = (PrivateKey) cipher.unwrap(keyBytes, "RSA", Cipher.PRIVATE_KEY);
        return Hex.encodeHexString(privateKey.getEncoded());
    }

    public static PublicKey getPublicKeyFromCA(Path certificatePath, String certificationType) throws Exception {
        CertificateFactory certificateFactory = CertificateFactory.getInstance(certificationType);
        try (FileInputStream in = new FileInputStream(certificatePath.toFile())) {
            Certificate certificate = certificateFactory.generateCertificate(in);
            return certificate.getPublicKey();
        }
    }

    public static PublicKey getPublicKeyFromKeyStore(Path keyStorePath, String alias, String password, String keyStoreType) throws Exception {
        try (FileInputStream is = new FileInputStream(keyStorePath.toFile())) {
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(is, password.toCharArray());
            return keyStore.getCertificate(alias).getPublicKey();
        }
    }

    public static PrivateKey getPrivateKeyFromKeyStore(Path keyStorePath, String alias, String password, String keyStoreType) throws Exception {
        try (FileInputStream is = new FileInputStream(keyStorePath.toFile())) {
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(is, password.toCharArray());
            return (PrivateKey) keyStore.getKey(alias, password.toCharArray());
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/156763.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【强训】Day06

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录一、选择二、编程1. 不要二2. 把字符串转换成整数答案1. 选择2. 编程普通小孩也要热爱生活&#xff01; 一、选择 关于抽象类与最终类&#xff0c;下列说法错误的是&#xff1f; A 抽象类能被继承&#xff0c;最终…

C语言零基础项目:六边形扫雷寻宝模式,详细思路+源码分享

程序简介六边形扫雷&#xff0c;寻宝模式&#xff0c;稍稍介绍一下。他也是要把所有安全的地方点出来。他没有扫雷模式的消零算法。每一个安全的点都需要单独挖出来&#xff0c;一次显示一个格子。添加了生命值的概念&#xff0c;也就是说存在一定的容错。显示的数字有别于扫雷…

亚马逊云科技 2022 re:Invent 观察 | 天下武功,唯快不破

引子“天下武功&#xff0c;无坚不摧&#xff0c;唯快不破”&#xff0c;相信大家对星爷电影《功夫》中的这句话耳熟能详。实际上&#xff0c;“天下武功&#xff0c;唯快不破”最早出自古龙先生的著名武侠小说《小李飞刀》&#xff1a;“小李飞刀&#xff0c;例无虚发&#xf…

LeetCode(String) 2325. Decode the Message

1.问题 You are given the strings key and message, which represent a cipher key and a secret message, respectively. The steps to decode message are as follows: Use the first appearance of all 26 lowercase English letters in key as the order of the substit…

React生命周期详解

React 类组件生命周期 React 有两个重要阶段 render 阶段和 commit 阶段&#xff0c;React 在调和( render )阶段会深度遍历 React fiber 树&#xff0c;目的就是发现不同( diff )&#xff0c;不同的地方就是接下来需要更新的地方&#xff0c;对于变化的组件&#xff0c;就会执…

Linux杂谈之java命令

一 java &#xff08;1&#xff09;基本解读 ① JAVA8 官方命令行参数 linux版的java 重点关注&#xff1a; java、javac、jar、keytool 这三个参数学习方式&#xff1a; 通过man java和官方文档快速学习 如何在官网搜索 java的命令行参数用法 ② 语法格式 ③ 描述 1)…

Java开发为何深入人心 ?我来带你解开 Spring、IoC、DI 的秘密~

目录 一、什么是Spring? 1.1、什么是容器&#xff1f; 1.2、IoC是什么&#xff1f; 1.3、IoC带来了什么好处&#xff1f; 二、什么是DI&#xff1f; 2.1、IoC和DI有什么关系&#xff1f; 一、什么是Spring? 一句概括&#xff0c;Spring 是包含了众多⼯具⽅法的 IoC 容器…

RHCE第七天之防火墙详解

文章目录一、 基本概念二、iptables三、firewalld四、实验练习一、 基本概念 什么是防火墙&#xff1f;路由策略和策略路由/ipsec vpn gre hdlc ppp 硬件 iDS 在计算中&#xff0c;防火墙是基于预定安全规则来监视和控制传入和传出网络流量的网络安全系统。该计算机流入流出的…

React基础梳理,万字总结,总能帮到你~

第1章&#xff1a;React入门 1.1.React简介 1.英文官网: reactjs.org/2.中文官网: react.docschina.org/3.用于动态构建用户界面的 JavaScript 库(只关注于视图)4.Facebook开源 React的特点 1.声明式编码2.组件化编码3.React Native 编写原生应用4.高效&#xff08;优秀的D…

CodeCraft-22 and Codeforces Round #795 (Div. 2)

A. Beat The Odds 题目链接&#xff1a; Problem - A - Codeforces 样例输入&#xff1a; 2 5 2 4 3 6 8 6 3 5 9 7 1 3样例输出&#xff1a; 1 0题意&#xff1a;给定一个长度为n的数组&#xff0c;我们可以对这个数组进行操作&#xff0c;每次操作可以删除一个数&#xff…

计算机防勒索病毒之系统主机加固篇

​ 近年来&#xff0c;计算机以及互联网应用在中国得到普及和发展&#xff0c;已经深入到社会每个角落&#xff0c;政府&#xff0c;经济&#xff0c;军事&#xff0c;社会&#xff0c;文化和人们生活等各方面都越来越依赖于计算机和网络&#xff0c;电子政务&#xff0c;无纸办…

如何把WPS转换成PDF格式?新手也能轻松学会的方法

WPS文件是我们工作中必不可少的&#xff0c;它可以编辑文本、记录数据、展示文档等等&#xff0c;都能更好的帮我们处理工作&#xff0c;不过有的时候WPS文件在不同设备上打开可能会出现格式错误或者乱码等一系列的问题&#xff0c;这时候我们就可以将WPS文件转换成PDF文件&…

[Leetcode] 传递信息(有向图路径)

小朋友 A 在和 ta 的小伙伴们玩传信息游戏&#xff0c;游戏规则如下&#xff1a;有 n 名玩家&#xff0c;所有玩家编号分别为 0 &#xff5e; n-1&#xff0c;其中小朋友 A 的编号为 0每个玩家都有固定的若干个可传信息的其他玩家&#xff08;也可能没有&#xff09;。传信息的…

Python数据分析之Pandas

文章目录前言一、输入输出1.1 txt1.2 csv1.3 excel1.4 json1.5 sql1.6 html1.7 latex二、数据结构2.1 一维数据 Series2.2 二维数据 DataFrame2.2.1 数据查看2.2.2 数据遍历2.2.3 数据选取2.2.4 数据处理2.2.5 数据统计2.3 索引对象 Index2.4 时间戳 TimeStamp三、窗口函数3.1 …

【每日一题】【LeetCode】【第十天】只出现一次的数字

解决之路 题目描述 测试案例&#xff08;部分&#xff09; 第一次 和昨天的题目有点类似&#xff0c;昨天是找重复&#xff0c;今天是找不重复。那直接按昨天第二次思路来写这次的代码。 class Solution(object):def singleNumber(self, nums):nums.sort()for i in range(l…

在线计算lncRNA-mRNA共表达相关系数,并使用cytoscape绘制共表达网络图

长链非编码RNA(Long noncoding RNA)是一类长度大于200 nt&#xff0c;不编码蛋白质的RNA。LncRNA的功能多样&#xff0c;如图1所示&#xff0c;A&#xff1a;充当蛋白质和染色质的连接因子&#xff0c;引起染色质重构&#xff08;chromatin remodeling&#xff09;&#xff1b;…

内存函数细节及实现

1、memcpy内存拷贝 不仅可以拷贝&#xff0c;还可以拷贝整型、结构体等&#xff0c;因为直接拷贝了内存。 因为不知道要拷贝的类型是什么&#xff0c;所以都用void*来接收。num是拷贝的字节数 拷贝时可任意选择dest&#xff0c;src&#xff0c;以及字节数。返回void*类型的指…

01什么是FPGA?

FPGA 是一种硬件可重构的体系结构。它的英文全称是Field Programmable Gate Array&#xff0c;中文名是现场可编程门阵列。 FPGA就是一个可以通过编程来改变内部结构的芯片&#xff0c;FPGA常年来被用作专用芯片&#xff08;ASIC&#xff09;的小批量替代品&#xff0c; 同时也…

PMP考试流程是怎么样的?

别的问题我可能不太了解&#xff0c;但考试流程我绝对是非常清楚了&#xff01;话不多说&#xff0c;直接放流程给到大家&#xff0c;好歹通过考试了&#xff0c;基本的情况还是能给大家讲解一下的。希望能够给有需要的同学提供点帮助。 先把考试的流程看仔细了&#xff0c;之…

核心乐理---音程名称

定义 音程是连个音之间的距离&#xff0c;是音乐中的距离&#xff0c;可以便于我们描述音符间的距离&#xff0c;便于与他人进行沟通交流。 就好像是厘米&#xff0c;米这些这些物理中的长度单位一样 度 度是音程的单位。 从一个音的名字念到另一个音的名字&#xff0c;一共念…