精华内容
下载资源
问答
  • 数字签名的应用

    千次阅读 2016-07-31 21:54:01
    a) 公钥加密系统允许任何人在分送信息时候使用公钥进行加密,数字签名能够让信息接受者确认信息发送者身份,接受者只能在密码系统尚未破译情况下才有理由确信发送者真实身份 b) 鉴权重要性尤其体现在...

    1. 鉴权

    a) 公钥加密系统允许任何人在分送信息的时候使用公钥进行加密,数字签名能够让信息接受者确认信息发送者的身份,接受者只能在密码系统尚未破译的情况下才有理由确信发送者的真实身份

    b) 鉴权的重要性尤其体现在银行的财务系统上,比如一个存款的指令从分行发送到中央银行,格式为(a,b),其中a是账号,b是金额,一位远程客户可以先存入100元然后观察传输的结果,然后接二连三的发送格式为(a,b)的数据,这种攻击方法为重放攻击

    2. 完整性

    a) 完整性指的是传输数据的双方都不希望数据被篡改,加密操作可以使第三方读取数据非常困难,然而第三方仍然可以采用可行的方法在传输中修改数据,一个通俗的例子就是同形攻击,比如上面例子中说的(a,b)的发送格式,一个远程用户可以先存入100元然后看拦截的传输结果,再进行篡改为(a,c),c为另一个金额

    3. 不可抵赖

    a) 在密文背景下,抵赖这个词的意思是不承认与消息有关的举动(即声称消息来自第三方),消息的接收方可以通过数字签名来防止其抵赖行为,因为接收方可以通过出示签名的方式来证明信息的来源

    首发于我的个人网站: 点击打开链接

    展开全文
  • 数字签名应用 电子投票 盲签名 群签名 数字签名新技术
  • 数字签名的应用示例

    2020-04-19 15:18:03
    最近要开发一个对外部系统提供服务接口,计划用数字签名进行接口安全性校验,网上查找资料后,写了一个示例如下 前言 示例项目中用到算法及jar包版本如下: 消息摘要算法为MD5 签名算法为SHA256withRSA...

     

     

     

     

     

     

    最近要开发一个对外部系统提供服务的接口,计划用数字签名进行接口的安全性校验,网上查找资料后,使用签名算法写了一个示例程序如下

    目录

    前言

    数字签名简介

    数字签名流程

    公私钥对的生成

    服务架构示意图

    服务端和客户端约定

    服务端项目digital-signature-server

    客户端项目digital-signature-client

    测试结果



    • 前言

    示例项目中用到的算法及jar包版本如下:

    消息摘要算法为MD5

    签名算法为SHA256withRSA

    项目基于springboot-2.2.5.RELEASE

    json采用albaba的fastjson-1.2.48


    • 数字签名简介

    数字签名是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。数字签名是非对称密钥加密技术与数字摘要技术的应用。数字签名具有不可篡改性和不可抵赖性等特征,常用的数字签名算法有RSA,DSA,ECDSA等等。


    • 数字签名流程

    • 消息发送:

    (1)消息发送者A使用消息摘要算法生成原文的数字摘要。

    (2) 使用A自己的私钥加密数字摘要。

    (3)将原文和加密之后的摘要发送给接收者B。

    • 消息接收:

    (1)消息接收者B接收到消息之后,使用A的公钥对摘要解密。(A的公钥是公开的)

    (2)B使用同样的摘要算法将所接收到的原文作为输入,生成数字摘要。

    (3)将第2步所生成的摘要与第1步解密得到的摘要进行比较。如果相同,表示原文没有被篡改;如果不同,则被篡改了。


    • 公私钥对的生成

    公私钥对的生成有多种方式,本次采用java代码生成的方式,具体代码如下:

    Base64工具类:

    import org.apache.commons.codec.binary.Base64;
    
    public class Base64Util {
    
        public static byte[] decodeBase64(String str){
            Base64 base64=new Base64();
            return base64.decode(str.getBytes());
        }
    
        public static String encodeBase64(byte[] b){
            Base64 base64=new Base64();
            return new String(base64.encode(b));
        }
    }

     公私钥对生成工具类:

    package com.qianglittle.problem;
    
    import com.qianglittle.problem.util.Base64Util;
    
    import java.security.Key;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.util.HashMap;
    import java.util.Map;
    
    public class KeyGenerator {
        private static final String KEY_ALGORITHM="RSA";
        private static final String PUBLIC_KEY="publicKey";
        private static final String PRIVATE_KEY="privateKey";
        private static Map<String,Key> keyMap;
        public static void initKey() throws Exception{
            KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);
            keyPairGenerator.initialize(1024);
            KeyPair keyPair=keyPairGenerator.generateKeyPair();
            RSAPublicKey publicKey=(RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey=(RSAPrivateKey) keyPair.getPrivate();
            keyMap= new HashMap<>(2);
            keyMap.put(PUBLIC_KEY,publicKey);
            keyMap.put(PRIVATE_KEY,privateKey);
        }
    
        public static String getPublicKeyStr(){
            Key key=keyMap.get(PUBLIC_KEY);
            return Base64Util.encodeBase64(key.getEncoded());
        }
    
        public static String getPrivateKeyStr(){
            Key key=keyMap.get(PRIVATE_KEY);
            return Base64Util.encodeBase64(key.getEncoded());
        }
    
        public static void main(String[] args) throws Exception {
            initKey();
            String privateKey=getPrivateKeyStr();
            String publicKey=getPublicKeyStr();
            System.out.println("privateKey:"+privateKey);
            System.out.println("publicKey:"+publicKey);
        }
    }
    

    运行main方法即可生成公私钥对,效果如下:


    • 服务架构示意图


    • 服务端和客户端约定

    系统对接前

    服务端生成自己的公私钥对,保存自己的私钥,然后将公钥发送给客户端

    客户端也生成自己的公私钥对,保存自己的私钥,然后将公钥发送给服务端

    服务端和客户端使用统一的类RequestBody和ResponseBody来处理请求及响应,请求、响应、签名分别封装进request、response、signature变量中代码如下:

    public class RequestBody {
        private String request;
        private String signature;
    
        public String getRequest() {
            return request;
        }
    
        public void setRequest(String request) {
            this.request = request;
        }
    
        public String getSignature() {
            return signature;
        }
    
        public void setSignature(String signature) {
            this.signature = signature;
        }
    }
    public class ResponseBody {
        private String response;
        private String signature;
    
        public ResponseBody(String response, String signature) {
            this.response = response;
            this.signature = signature;
        }
    
        public String getResponse() {
            return response;
        }
    
        public void setResponse(String response) {
            this.response = response;
        }
    
        public String getSignature() {
            return signature;
        }
    
        public void setSignature(String signature) {
            this.signature = signature;
        }
    }

    客户端发送请求时,进行如下操作:

    1.将请求参数由Java类转换为json字符串(即RequestBody中的request)

    2.使用MD5算法生成request的摘要(digestMessage)

    3.客户端使用自己的私钥生成签名(即RequestBody中的signature)

    4.发送RequestBody

    5.接收服务端响应并转换为ResponseBody类型的变量

    6.使用服务端公钥验签

    客户端发送请求示例代码:

    public void sendRequestDemo(Person person) {
            //将参数转换为json字符串
            String reqStr = JSON.toJSONString(person);
            //生成摘要
            String digestMessage = messageDigestService.digest(reqStr);
            //生成数字签名
            String signature = digitalSignService.sign(digestMessage);
            //将请求和签名封装进RequestBody类型的变量中
            RequestBody requestBody = new RequestBody();
            requestBody.setRequest(reqStr);
            requestBody.setSignature(signature);
            try {
                //发送请求
                URI uri = new URI("http://localhost:8080/person/test");
                RestTemplate tlp = new RestTemplate();
                String responseBodyStr = tlp.postForObject(uri, requestBody, String.class);
                //将响应转换为ResponseBody类型
                ResponseBody responseBody = JSON.parseObject(responseBodyStr, ResponseBody.class);
                String responseStr = responseBody.getResponse();
                System.out.println("客户端responseStr:" + responseStr);
                String responseSignature = responseBody.getSignature();
                System.out.println("客户端responseSignature:" + responseSignature);
                String responseDigest = messageDigestService.digest(responseStr);
                //使用服务端公钥对响应进行验签
                boolean verify = digitalSignService.verify(responseSignature, responseDigest);
                System.out.println("客户端验签结果:" + verify);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    服务端接收请求后,对请求进行如下操作:

    1.获取request和signature

    2.使用MD5算法生成request的摘要(digestMessage)

    3.服务端使用客户端的公钥验签

    4.若验签失败则返回“验签失败”

    5.若验签成功,则对请求进行处理

    6.将要返回的结果由java类转换为json字符串(即ResponseBody中的response)

    7.使用MD5算法生成response的摘要(digestMessage)

    8.服务端使用自己的私钥生成签名(即ResponseBody中的signature)

    9.返回ResponseBody


    • 服务端项目digital-signature-server

    创建一个spirngboot项目,作为服务端

    项目文件清单如下

    pom.xml如下

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.5.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.xxx.xxx</groupId>
        <artifactId>digital-signature-server</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>digital-signature-server</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.6</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.48</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    secretKey.properties保存服务端私钥和客户端公钥

    clientPublicKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcfg5Ng2vd9XiSXFVSgGIuH4MIm+i+WH56grv2DtcoXxNb/kxbjCQGfZnqNERhk58Qt2ly+IlIKMil9HMFVd42bOmN3ngGOFcFLidaeaWiMvPFWut854zr4lLb0Gzu16iT/u4tF2/Oq6nItOMnQaJStr5jLKyFzgdwgN6876GdawIDAQAB
    serverPrivateKey=MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJx+Dk2Da931eJJcVVKAYi4fgwib6L5YfnqCu/YO1yhfE1v+TFuMJAZ9meo0RGGTnxC3aXL4iUgoyKX0cwVV3jZs6Y3eeAY4VwUuJ1p5paIy88Va63znjOviUtvQbO7XqJP+7i0Xb86rqci04ydBolK2vmMsrIXOB3CA3rzvoZ1rAgMBAAECgYA7NiL5RzmgIQn+7vrFnZgIdZnhvwQgSWGJvz+ZSWI1f0vW6fBAT1UuM4XyLNaWyQFNlOhMPSfMasoIqOaAZU4PWCEP+kVA9iDRCCFxF2fJfMCOnrOx5o79S5yH/AoUWAc5kABaNG4Dg1koIg+0UV+sFZ42925mvSpkXw/dhVypUQJBANHm948fB/HvduC/UgZ3rJh74DHj54I3Fnle6twI/K6DMKCjaUtwKjvvQxtMzgk4rvomhD1WYIIPKXixhDW2u4kCQQC+3E4nPLbCBjtCDjvqcRC9OmxZIAYw/p6S68ohk8BrXhdCO5YwPaCPryvHxx1Hht84N8/YWhPKwWP0Yif6iFBTAkAGJxAAmPdBpzRD2DfOSrm7an4i2DxT+8tj2V1m/7hwYRYOz1tpw6rpQNUlurWbXZb7bB+aMKr5hPpBOGrYrDeJAkAu9QzVYn6kZdwWeGINYBv6MnGNy+86BqsFArYMZMmmoNOgHADrhX4HW9WtpTNy8Z/huPmOBTtxWvs4mR206ey5AkBprGTeD+iONcsn975sbiGXRSqgZ+LmbDw//J3CVUzV7tKCtULukz8HA8GhNNH//H13iPkd9KTGkmYkqnxYFlQ6

     KeyConfig读取secretKey.properties配置

    @Configuration
    @PropertySource(value="classpath:secretKey.properties")
    public class KeyConfig {
    
    
        @Value("${serverPrivateKey}")
        private String serverPrivateKey;
    
        @Value("${clientPublicKey}")
        private String clientPublicKey;
    
        public String getServerPrivateKey() {
            return serverPrivateKey;
        }
    
        public void setServerPrivateKey(String serverPrivateKey) {
            this.serverPrivateKey = serverPrivateKey;
        }
    
        public String getClientPublicKey() {
            return clientPublicKey;
        }
    
        public void setClientPublicKey(String clientPublicKey) {
            this.clientPublicKey = clientPublicKey;
        }
    }
    

     PublicAndPrivateKeyBuilder初始化服务端私钥和客户端公钥对并生成相应的bean

    @Component
    public class PublicAndPrivateKeyBuilder {
    
        @Resource
        KeyConfig keyConfig;
    
        @Bean
        public PrivateKey initServerPrivateKey() {
            try {
                String privateKey = keyConfig.getServerPrivateKey();
                if (privateKey != null && privateKey.trim().length() != 0) {
                    byte[] privateKeys;
                    privateKeys = Base64Util.decodeBase64(privateKey);
                    PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeys);
                    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                    return keyFactory.generatePrivate(privateKeySpec);
                }
                return null;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        @Bean
        public PublicKey initClientPublicKey() {
            try {
                String publicKey = keyConfig.getClientPublicKey();
                if (publicKey != null && publicKey.trim().length() != 0) {
                    byte[] publicKeys;
                    publicKeys = Base64Util.decodeBase64(publicKey);
                    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeys);
                    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                    return keyFactory.generatePublic(publicKeySpec);
                }
                return null;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    

     MessageDigestBuilder生成MD5消息摘要算法MessageDigest对应的bean

    @Component
    public class MessageDigestBuilder {
    
        @Bean
        public MessageDigest messageDigestInit(){
            try{
                return MessageDigest.getInstance("MD5");
            }catch(NoSuchAlgorithmException e){
                e.printStackTrace();
                return null;
            }
        }
    }
    

    消息摘要和签名服务MessageDigestService,DigitalSignService

    @Service
    public class MessageDigestServiceImpl implements MessageDigestService {
    
        private String CHARSET_UTF8 = "UTF-8";
    
        @Resource
        MessageDigest messageDigest;
    
        @Override
        public String digest(String srcMessage) {
            try {
                byte[] digestByteArray = messageDigest.digest(srcMessage.getBytes(CHARSET_UTF8));
                return Base64Util.encodeBase64(digestByteArray);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    @Service
    public class DigitalSignServiceImpl implements DigitalSignService {
    
        /**
         * 默认编码
         */
        private static final String DEFAULT_ENCODING = "UTF-8";
    
        /**
         * 签名算法
         */
        private static final String SIG_ALGORITHM="SHA256withRSA";
    
        @Resource
        PublicKey publicKey;
    
        @Resource
        PrivateKey privateKey;
    
        @Override
        public String sign(String unsigned) {
            String signed=null;
            try{
                byte sigData[];
                byte sourceData[] = unsigned.getBytes(DEFAULT_ENCODING);
                Signature sig=Signature.getInstance(SIG_ALGORITHM);
                sig.initSign(privateKey);
                sig.update(sourceData);
                sigData=sig.sign();
                signed=Base64Util.encodeBase64(sigData);
            }catch(Exception e){
                e.printStackTrace();
            }
            return signed;
        }
    
        @Override
        public boolean verify(String signature, String unsigned) {
            boolean valid=false;
            try{
                byte sourceData[] = unsigned.getBytes(DEFAULT_ENCODING);
                byte sigData[]=Base64Util.decodeBase64(signature);
                Signature sig=Signature.getInstance(SIG_ALGORITHM);
                sig.initVerify(publicKey);
                sig.update(sourceData);
                valid=sig.verify(sigData);
            }catch(Exception e){
                e.printStackTrace();
            }
            return valid;
        }
    }

    SignatureRequestWrapper:请求包装类,重写getInputStream方法,将RequestBody的request部分转发给controller 

    public class SignatureRequestWrapper extends HttpServletRequestWrapper {
        private final RequestBody requestBody;
    
        public RequestBody getRequestBody() {
            return requestBody;
        }
    
        public SignatureRequestWrapper(final HttpServletRequest req) throws IOException {
            super(req);
            StringBuilder sb = new StringBuilder();
            String line;
            BufferedReader reader = req.getReader();
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            requestBody = JSONObject.parseObject(sb.toString(), RequestBody.class);
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody.getRequest().getBytes());
            return new ServletInputStream() {
                @Override
                public boolean isFinished() {
                    return false;
                }
    
                @Override
                public boolean isReady() {
                    return false;
                }
    
                @Override
                public void setReadListener(ReadListener readListener) {
                }
    
                @Override
                public int read() throws IOException {
                    return bais.read();
                }
            };
        }
    
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(this.getInputStream()));
        }
    }
    

     SignatureResponseWrapper,响应包装类,重写getOutputStream方法,获取controller返回的原始响应数据,由SignatureFilter对响应数据进行加签操作

    
    public class SignatureResponseWrapper extends HttpServletResponseWrapper {
    
        private ByteArrayOutputStream buffer;
    
        private ServletOutputStream out;
    
        public SignatureResponseWrapper(HttpServletResponse httpServletResponse) {
            super(httpServletResponse);
            buffer = new ByteArrayOutputStream();
        }
    
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            out = new ServletOutputStream() {
                @Override
                public void write(int b) throws IOException {
                    buffer.write(b);
                }
    
                @Override
                public boolean isReady() {
                    return false;
                }
    
                @Override
                public void setWriteListener(WriteListener writeListener) {
                }
            };
            return out;
        }
    
        @Override
        public void flushBuffer() throws IOException {
            if (out != null) {
                out.flush();
            }
        }
    
        public byte[] getContent() throws IOException {
            return buffer.toByteArray();
        }
    }
    

     SignatureFilter,签名过滤器,对请求进行验签,对响应进行加签操作

    @WebFilter(urlPatterns = {"/person/test"})
    public class SignatureFilter implements Filter {
        @Resource
        DigitalSignService digitalSignService;
    
        @Resource
        MessageDigestService messageDigestService;
    
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response=(HttpServletResponse) servletResponse;
            try {
                SignatureRequestWrapper signatureRequestWrapper = new SignatureRequestWrapper(request);
                SignatureResponseWrapper signatureResponseWrapper=new SignatureResponseWrapper(response);
                String requestStr = signatureRequestWrapper.getRequestBody().getRequest();
                String requestSignature = signatureRequestWrapper.getRequestBody().getSignature();
                System.out.println("服务端filter接收到requestStr:" + requestStr);
                System.out.println("服务端filter接收到requestSignature:" + requestSignature);
                String requestDigest = messageDigestService.digest(requestStr);
                //对请求验签
                boolean verify = digitalSignService.verify(requestSignature, requestDigest);
                System.out.println("服务端验签结果:" + verify);
                if (verify) {
                    filterChain.doFilter(signatureRequestWrapper, signatureResponseWrapper);
                    String responseStr=new String(signatureResponseWrapper.getContent(),"UTF-8");
                    System.out.println("服务端filter获取到responseStr: " +responseStr);
                    //对响应加签
                    String responseDigest = messageDigestService.digest(responseStr);
                    String responseSignature = digitalSignService.sign(responseDigest);
                    ResponseBody responseBody=new ResponseBody(responseStr,responseSignature);
                    System.out.println("服务端filter生成的responseSignature: " +responseSignature);
                    response.setContentLength(JSON.toJSONBytes(responseBody).length);
                    response.getOutputStream().write(JSON.toJSONBytes(responseBody));
                } else {
                    servletResponse.getWriter().println("验签失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void destroy() {
    
        }
    }

    服务端controller

    @RestController
    @RequestMapping("/person")
    public class PersonController {
        @RequestMapping("/test")
        public Person test(@RequestBody Person person) {
            String personStr = "person.name:" + person.getName() + ",person.address:" + person.getAddress();
            System.out.println("服务端controller接收到请求:"+personStr);
            return person;
        }
    }

    实体类Person

    public class Person {
    
        String name;
    
        String address;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    

    • 客户端项目digital-signature-client

    文件清单如下

    pom.xml如下

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.5.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.xxx.xxx</groupId>
        <artifactId>digital-signature-client</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>digital-signature-server</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.6</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.48</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
     

    secretKey.properties如下,包含客户端私钥和服务端公钥

    serverPublicKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcfg5Ng2vd9XiSXFVSgGIuH4MIm+i+WH56grv2DtcoXxNb/kxbjCQGfZnqNERhk58Qt2ly+IlIKMil9HMFVd42bOmN3ngGOFcFLidaeaWiMvPFWut854zr4lLb0Gzu16iT/u4tF2/Oq6nItOMnQaJStr5jLKyFzgdwgN6876GdawIDAQAB
    clientPrivateKey=MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJx+Dk2Da931eJJcVVKAYi4fgwib6L5YfnqCu/YO1yhfE1v+TFuMJAZ9meo0RGGTnxC3aXL4iUgoyKX0cwVV3jZs6Y3eeAY4VwUuJ1p5paIy88Va63znjOviUtvQbO7XqJP+7i0Xb86rqci04ydBolK2vmMsrIXOB3CA3rzvoZ1rAgMBAAECgYA7NiL5RzmgIQn+7vrFnZgIdZnhvwQgSWGJvz+ZSWI1f0vW6fBAT1UuM4XyLNaWyQFNlOhMPSfMasoIqOaAZU4PWCEP+kVA9iDRCCFxF2fJfMCOnrOx5o79S5yH/AoUWAc5kABaNG4Dg1koIg+0UV+sFZ42925mvSpkXw/dhVypUQJBANHm948fB/HvduC/UgZ3rJh74DHj54I3Fnle6twI/K6DMKCjaUtwKjvvQxtMzgk4rvomhD1WYIIPKXixhDW2u4kCQQC+3E4nPLbCBjtCDjvqcRC9OmxZIAYw/p6S68ohk8BrXhdCO5YwPaCPryvHxx1Hht84N8/YWhPKwWP0Yif6iFBTAkAGJxAAmPdBpzRD2DfOSrm7an4i2DxT+8tj2V1m/7hwYRYOz1tpw6rpQNUlurWbXZb7bB+aMKr5hPpBOGrYrDeJAkAu9QzVYn6kZdwWeGINYBv6MnGNy+86BqsFArYMZMmmoNOgHADrhX4HW9WtpTNy8Z/huPmOBTtxWvs4mR206ey5AkBprGTeD+iONcsn975sbiGXRSqgZ+LmbDw//J3CVUzV7tKCtULukz8HA8GhNNH//H13iPkd9KTGkmYkqnxYFlQ6

    applicaton.properties如下,设置服务启动端口为8081

    server.port=8081

    KeyConfig.java读取secretKey.properties配置 

    @Configuration
    @PropertySource(value="classpath:secretKey.properties")
    public class KeyConfig {
    
    
        @Value("${clientPrivateKey}")
        private String clientPrivateKey;
    
        @Value("${serverPublicKey}")
        private String serverPublicKey;
    
        public String getClientPrivateKey() {
            return clientPrivateKey;
        }
    
        public void setClientPrivateKey(String clientPrivateKey) {
            this.clientPrivateKey = clientPrivateKey;
        }
    
        public String getServerPublicKey() {
            return serverPublicKey;
        }
    
        public void setServerPublicKey(String serverPublicKey) {
            this.serverPublicKey = serverPublicKey;
        }
    }
    

    PublicAndPrivateKeyBuilder初始化客户端私钥和服务端公钥对并生成相应的bean

    @Component
    public class PublicAndPrivateKeyBuilder {
    
        @Resource
        KeyConfig keyConfig;
    
        @Bean
        public PrivateKey initClientPrivateKey() {
            try {
                String privateKey = keyConfig.getClientPrivateKey();
                if (privateKey != null && privateKey.trim().length() != 0) {
                    byte[] privateKeys;
                    privateKeys = Base64Util.decodeBase64(privateKey);
                    PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeys);
                    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                    return keyFactory.generatePrivate(privateKeySpec);
                }
                return null;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        @Bean
        public PublicKey initServerPublicKey() {
            try {
                String publicKey = keyConfig.getServerPublicKey();
                if (publicKey != null && publicKey.trim().length() != 0) {
                    byte[] publicKeys;
                    publicKeys = Base64Util.decodeBase64(publicKey);
                    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeys);
                    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                    return keyFactory.generatePublic(publicKeySpec);
                }
                return null;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    

     SignatureController,测试客户端发送请求到服务端,并对服务端响应进行处理

    @RestController
    @RequestMapping("/signature")
    public class SignatureController {
    
        @Resource
        MessageDigestService messageDigestService;
    
        @Resource
        DigitalSignService digitalSignService;
    
        @RequestMapping("/sendRequest")
        public ResponseBody sendRequest(Person person) {
            String reqStr = JSON.toJSONString(person);
            String digestMessage = messageDigestService.digest(reqStr);
            String signature = digitalSignService.sign(digestMessage);
            RequestBody requestBody = new RequestBody();
            requestBody.setRequest(reqStr);
            requestBody.setSignature(signature);
            try {
                URI uri = new URI("http://localhost:8080/person/test");
                RestTemplate tlp = new RestTemplate();
                String responseBodyStr = tlp.postForObject(uri, requestBody, String.class);
                ResponseBody responseBody = JSON.parseObject(responseBodyStr, ResponseBody.class);
                String responseStr = responseBody.getResponse();
                System.out.println("客户端responseStr:" + responseStr);
                String responseSignature = responseBody.getSignature();
                System.out.println("客户端responseSignature:" + responseSignature);
                String responseDigest = messageDigestService.digest(responseStr);
                //对响应进行验签
                boolean verify = digitalSignService.verify(responseSignature, responseDigest);
                System.out.println("客户端验签结果:" + verify);
                sendRequestDemo(person);
                return responseBody;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
       
    }

    其他文件同服务端一致


    • 测试结果

    启动服务端和客户端

    使用postman发送请求,url及参数如下图

    服务端控制台输出如下图

    客户端控制台输出如下图

     

    展开全文
  • 数字签名的应用实例

    千次阅读 2018-09-24 20:30:53
    在这样情况下,就可以使用数字签名,即该组织可以对警告信息文件施加数字签名,这样一来世界上所有人就都可以验证警告信息发布者是否合法。 消息发布目的是尽量让更多人知道,因此我们没有必要对信息进行...

    一 安全信息公告

    一些信息安全方面的组织会在其网站上发布一些关于安全漏洞的警告,那么这些警告信息是否真的是该组织发布的呢?我们如何确认发布这些信息的网站没有被第三方篡改呢?

    在这样的情况下,就可以使用数字签名,即该组织可以对警告信息的文件施加数字签名,这样一来世界上所有人就都可以验证警告信息的发布者是否合法。

    消息发布的目的是尽量让更多的人知道,因此我们没有必要对信息进行加密,但是必须排除有人恶意伪装成该组织来发布假消息的风险。因此,我们不加密消息,而只是对消息加上数字签名,这种对明文消息所施加的签名,一般称为明文签名。

    例如:

    二 软件下载

    当我们从网上下载软件,我们需要判断所下载的软件是否可以安全运行,因为下载的软件有可能被主动攻击这Mallory篡改,从而执行一些恶意的操作。例如,明明是下载一个游戏软件,结果却可能是一个会删除硬盘上所有数据的程序,又或者可能是一个会将带有病毒邮件发送给所有联系人的程序。

    为了防止出现这样的问题,软件的作者可以对软件加上数字签名,而我们只要在下载之后验证数字签名,就可以识别出软件是否遭到主动攻击者Mallory的篡改。

    一种名为带签名的Applet的软件就是一个具体的例子。这种软件是用Java编写的,并加上了作者的签名,而浏览器会在下载之后对签名进行验证。

    不过,数字签名只是能够检测软件是否被篡改过,而不能保证软件本身不会做出恶意的行为。如果软件作者本身具有恶意的话,那么再怎么加上数字签名也是无法防范这种风险的。

    三 公钥证书

    在验证数字签名时我们需要合法的公钥,那么怎么才知道自己得到的公钥是否合法呢?我们可以将公钥当做消息,对它加上数字签名。像这样对公钥施加数字签名所得到的就是公钥证书。

    四 SSL/TLS

    SSL/TLS在认证服务器身份是否合法时会使用服务器证书,它就是加上了数字签名的服务器公钥。相对地,服务器为了对客户端(用户)进行认证也会使用客户端证书。

     

    展开全文
  • 关于数字签名的应用

    2016-04-24 15:39:58
    数字签名这个东西是用来进行通信的一种验证方式,但是与传统相区别的是数字签名的作用是用于验证,也就是说数字签名的目的并不是让可能在网络环境下的第三方无法获得传输的信息,而是保护信息在传输中的正确性,即使...

             数字签名这个东西是用来进行通信的一种验证方式,但是与传统相区别的是数字签名的作用是用于验证,也就是说数字签名的目的并不是让可能在网络环境下的第三方无法获得传输的信息,而是保护信息在传输中的正确性,即使存在监听的第三方,第三方也只能获取信息但是无法对于信息进行篡改。

            数字签名的原理其实非常简单,传输的内容将会有两个部分组成,第一个就是内容,内容与完全不加密的内容一致,第二部分就是密文,也就是将所要传输的内容通过加密之后的数据。这两部分数据充分暴露了数字签名的使用意图,即使在网络环境之中存在监听,截取之类的,数字签名并不在乎是不是可能有第三方获取到了传输的内容,所以通信内容里有一部分是直接明文的。

            然后我们来谈谈数字签名如何完成其设计目的的------防止篡改和验证,数字签名的加密解密存在两个码,一个是公钥,一个是私钥。譬如存在以下情况A要向B传输数据然后要通过数字签名进行验证,这个时候A需要通过一个简单的方法生成一对公钥和私钥,然后A需要将公钥给B,这个时候B就可以用公钥解密A传输数据中的加密内容了。

           这种模式存在一个优点,就是不需要安全的管道来传输秘钥,因为在这里用来进行报文加密的私钥只有一个人知道--A,A不需要将私钥给任意一个人,这一点在很大程度上确保了加密时候的安全性。然后拿到公钥的B通过对于报文进行解密,获取到对应的明文内容,和数据中的第一部分(明文数据)进行对比,如果相符合的话就能够认为这个数据确实是从A那里发过来的。由于除了A以外没有其他人有私钥,而且在整个过程中A并不要把自己的私钥进行告诉其他人,所以在这里这个验证是相当有效力。

    展开全文
  • 基于XML数字签名的应用模型设计与分析论文
  • itextsharp 数字签名白皮书配套应用代码 该代码C#示例 详细解释如何通过itext对pdf文件签名和验证操作
  • 数字签名的原理和应用

    千次阅读 2020-12-15 09:15:05
    1.数字签名的原理 在日常生活中,签名的意义就是签完你的名后,别人可以知道这件事是你做的,而由于每个人笔迹不同,你也无法否认这个名字是你签的。同真实的签名一样,数字签名也是用来证明某条信息是本人发的,...
  • 数字签名的原理及其应用

    千次阅读 2018-03-24 00:27:26
    概述 我们日常都亲自签过各种名,...数字签名和这个类似,是用来保证一段信息不可伪造而且使这段信息产生者不可抵赖。 例如小明和二狗互不相识,碰巧在各自家里组局打王者荣耀,小明总抢二狗蓝爸爸,二狗怒了...
  • 这其中需要在经过数字签名的交易上打上一个可信赖的时间戳,从而解决一系列的实际和法律问题。由于用户桌面时间很容易改变,由该时间产生的时间戳不可信赖,因此需要一个权威第三方来提供可信赖的且不可抵赖的时间戳...
  • 基于schnorr算法的数字签名系统研究与应用
  • 数字签名原理及其应用

    万次阅读 多人点赞 2017-06-25 15:40:34
    签名的作用无非就是证明某个文件上的内容确实是我写的/我认同的,别人不能冒充我的签名(不可伪造),我也不能否认上面的签名是我的(不可抵赖)。 我们知道,手写签名之所以不能伪造,是因为每一个人的...而数字签名
  • 签名在生活中十分常见。当我们办理证件、签署协议时往往需要... 数字签名的应用在网上可以找到很多例子。这里可以参考某博主的文章。 数字签名是带密钥的消息摘要算法。密码学中有一个柯克霍夫原则——密码系统...
  • 数字签名

    2017-03-30 10:28:53
    数字签名原理 客户端处理 要传输的二进制数据可使用对称加密算法AES加密(报文) 对报文进行HASH提取报文摘要(指纹) ...数字签名的应用场景 需要严格验证发送方身份信息情况 使用数字签名能够让接收
  • Android应用数字签名详解

    万次阅读 2015-11-26 15:23:26
    查看第三方应用或Android系统应用签名证书信息概述Android系统要求所有的应用必须被证书进行数字签名之后才能进行安装。Android系统通过该证书来确认应用的作者,该证书是不需要权威机构认证的,一般情况下应用都是...
  • C#中对于发送的信息进行不对称加密及对其进行数字签名的实例应用
  • 有研究数字签名的同学可以来看一下,关于椭圆曲线的数字签名方面的研究
  • 数字签名在我国的应用及发展
  • 针对当前物流行业高成本的纸质签名,本文分析数字签名的优点,以液晶显示控制芯片SED1335和触摸屏控制芯片ADS7846为例,提出一种在手持式设备上实现数字签名采集的方法,给出硬件和软件的实现过程。
  • 2 Android使用数字签名的场景 2.1 未签名的APK VS 签名后的APK 2.2 应用层面:Android对APK的签名要求 2.2.1 Android拒绝安装没有签名的APK 2.2.2 Android不校验证书的合法性 2.2.3 当签名不匹配时,APK升级会...
  • 数字签名实际是非对称加密算法另一项主要应用领域,数字签名本身并没有引入任何新技术,但它比加解密应用的更加普遍。加解密解决了信息保密性问题,因为只有有密钥用户才能解密密文;而数字签名解决了信息...
  • 目录创建数字签名创建自签名证书确定待打包应用的颁发者(Subject)使用 New-SelfSignedCertificate 命令创建证书导出证书打包应用程序使用SignTool进行签名使用SignTool确定哈希算法对APP进行签名常见错误及解决 ...
  • 摘要:针对当前物流行业高成本的纸质签名,本文分析数字签名的优点,以液晶显示控制芯片SED1335和触摸屏控制芯片ADS7846为例,提出一种在手持式设备上实现数字签名采集的方法,给出硬件和软件的实现过程。...
  • 从移动运营商角度出发,研究分析了利用移动终端和SIM卡实现金融类应用用户数字签名认证技术要求,梳理了基于智能终端和智能卡安全技术,提出了基于电信智能卡金融类应用用户签名和身份认证技术架构和业务...
  • 在线数字签名验证 安装依赖项 npm install 在开发模式下启动应用程序(热代码重新加载,错误报告等) quasar dev 整理文件 npm run lint 构建用于生产的应用 quasar build 自定义配置 请参阅 。
  • 信息技术发展,大致分为电讯技术发明,19世纪30年代开始 , 计算机技术发展,20世纪50年代开始 ,和互联网使用 20世纪60年代开始三个阶段。...5.数字签名是非对称密钥加密技术与数字摘要技术综合应用
  • 数字签名的应用过程是,数据源发送方使用自己的私钥对数据校验和或其他与数据内容有关的变量进行加密处理,完成对数据的合法“签名”,数据接收方则利用对方的公钥来解读收到的“数字签名”,并将解读结果用于对数据...
  • Android应用的数字签名

    2012-03-26 16:58:28
    为什么要签名? 开发Android的人这么多,完全有可能大家都把类名,包名起成了一个同样的名字,这时候如何区分... APK如果使用一个key签名,发布时另一个key签名的文件将无法安装或覆盖老的版本,这样可以防止你已安装

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,786
精华内容 1,514
关键字:

数字签名的应用