计算机中的密码学

简介: 密码学是数学和计算机科学的分支,同时其原理涉及大量信息论。密码学的发展促进了计算机科学,特别是在于电脑与网络 安全所使用的技术,如访问控制与信息的机密性。信息的加密几乎在所有的信息通讯中都是很有必要的,尤其是金融类、机密类信息。所以,了解密码学和加密算法对于开发人员来说,也是很有必须的。


一、概述



密码学是数学和计算机科学的分支,同时其原理涉及大量信息论。密码学的发展促进了计算机科学,特别是在于电脑与网络 安全所使用的技术,如访问控制与信息的机密性。信息的加密几乎在所有的信息通讯中都是很有必要的,尤其是金融类、机密类信息。所以,了解密码学和加密算法对于开发人员来说,也是很有必须的。

微信图片1.png

摘要算法是一种单向加密算法,例如SHA、MD5等,这是一种数据完整性的加密,这种单向加密一般称为摘要,而不是真正意义上的加密。因为摘要不可逆,可以防止数据在传输过程中被篡改。可以用于用户登录时验证密码、接口请求时验证参数、文件传输时验证完整性等。

微信图片2.png

对称加密算法是一种基于密钥的加密与解密算法,例如DES、AES等,通信双方共享同一个密钥,双方在通信前商定该密钥,并妥善保管。对称加密有两种方式,一种基于固定密钥,另一种是基于随机源密钥。

微信图片3.png

非对称加密算法中加密使用的密钥和解密使用的密钥不同,一个公开的称为公钥,一个保密的称为私钥。通信双方都有一对自己的公私钥,私钥自己保管好,公钥提供给对方,例如DSA、RSA等。非对称加密的应用场景有两种,一种是公钥加密,私钥解密,另一种是私钥加密,公钥解密。

微信图片4.png对称加密和非对称加密

对称加密速度快、算法公开、计算量小、加密速度快、加密效率高,适用于加密大量数据,但通讯双方需要保护好密钥,存在密钥泄漏的安全风险,而且通讯方的密钥都不一样,所以所拥有的密钥数量巨大,密钥的管理会成为负担。

非对称加密公钥是公开的,私钥不对外公开,只需要维护自己的一组公钥和私钥,在密钥管理上更便利。非对称加密算法强度复杂,加解密算法速度没有对称加密的速度快,但这也保证了其安全性。

针对两种加密方式的优缺点,各大密码机构主张对称加密与非对称加密算法结合使用,使用对称加密算法加密内容,再使用非对称加密算法加密对称算法的密钥。

微信图片5.jpg

二、应用场景



MD5实现用户登录


在设计一个用户登录系统时,用户的密码不管是在网络传输中,还是存在数据库中,都不应该是明文。一般会选用摘要算法来对密码进行加密,在传输和存储时都是使用加密后的Hash密文。比如使用MD5对密码进行加密,在注册时将密码明文通过MD5加密,然后存储在数据库中,登录时客户端同样对密码进行加密,然后在服务端与数据库中的Hash密文对比,通过判断两个Hash密文是否一致来决定是是否登录成功。这样处理的好处是,即使数据库中的密码泄漏了,也不会知道密码明文。

微信图片6.png只要明文相同,MD5加密后的密文就相同,于是攻击者就可以通过撞库的方式来破解出明文。加盐就是向明文中加入随机数,然后在生成MD5,这样一来即使明文相同,每次生成的MD5码也不同,如此就加大了暴力破解的难度。


要算法实现参数验签


摘要算法可以任意大的数据压缩成摘要,使得数据量变小,将数据的格式转换成固定位数的Hash码。这可以给任何一种数据创建小的数字“指纹”,这就可以用来判断数据的完整性,判断数据在传输过程中是否被篡改,从而满足安全性需要。例如,我们要设计有一定安全性要求的接口,需要对接口参数进行完整性验证,可以在请求参数中添加一个字段存放所有业务字段的摘要Hash码,这样做的话,即使在接口请求的过程中被黑客攻击修改了参数信息,也不会成功请求服务,从而破坏正常业务。微信图片7.png


Git保证完整性


Git中所有数据在存储前都计算校验和,然后以校验和来引用。这意味着不可能在Git不知情时更改任何文件内容或目录内容。这个功能建构在Git底层,是构成Git哲学不可或缺的部分。若你在传送过程中丢失信息或损坏文件,Git就能发现。Git用以计算校验和的机制叫做SHA-1散列(摘要算法),它会基于Git中文件的内容或目录结构计算出来一个Hash码。

24b9da6552252987aa493b52f8696cd6d3b00373

Git中使用这种Hash码的情况很多,实际上,Git数据库中保存的信息都是以文件内容的Hash码来索引,而不是文件名。


非对称加密实现数字签名


数字签名是一种功能类似写在纸上的普通签名,使用非对称加密领域的技术,一套数字签名算法通常包括两种运算,一个用于签名,另一个用于验证。在使用非对称加密时,通常我们使用公钥加密,用私钥解密,而在数字签名中,我们使用私钥加密(生成签名),公钥解密(验证签名)。前面说过非对称加密算法的复杂性,所以通常我们会对消息内容的Hash值签名,因为Hash值长度远远小于消息原文,使得签名(非对称加密)的效率大大提高。

微信图片8.png

公钥和私钥都可以用于加解密操作,用公钥加密的数据只能由对应的私钥解密,反之亦然。虽说两者都可用于加密,但是不同场景使用不同的密钥来加密,当私钥用于签名,公钥用于验签时,签名和加密作用不同,签名并不是为了保密,而是为了保证这个签名是由特定的某个人签名的,而不是被其它人伪造的签名,所以私钥的私有性就适合用在签名用途上。私钥签名后,只能由对应的公钥解密,公钥又是公开的(很多人可持有),所以这些人拿着公钥来解密,解密成功后就能判断出是持有私钥的人做的签名,验证了身份合法性。

公钥加密,私钥解密,才是真正的加密;私钥加密,公钥解密用于签名。


SSH协议加密分析


SSH是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。SSH最常见的用途是远程登录系统,通常用来传输命令行界面和远程执行命令。SSH的使用在类Unix系统(Linux系统)最为常见,不过在Windows10 1809版本也提供了Open SSH工具。在使用SSH客户端登录时,SSH提供两种级别的安全验证:

  • 第一种级别(基于密码的安全验证),使用帐号和密码登录到远程主机,并且所有传输的数据都会被加密。但是,可能会有别的服务器在冒充真正的服务器,无法避免被“中间人”攻击。
  • 第二种级别(基于密钥的安全验证),需要依靠密钥,也就是你必须为自己创建一对密钥,并把公有密钥放在需要访问的服务器上。客户端会向服务器发出请求,请求用你的密钥进行安全验证。服务器收到请求之后,先在你在该服务器的用户根目录下寻找你的公有密钥,然后把它和你发送过来的公有密钥进行比较。如果两个密钥一致,服务器就用公有密钥加密“质询”(challenge)并把它发送给客户端软件。从而避免被“中间人”攻击。

微信图片9.pngSSH使用密钥验证时,使用了摘要算法和非对称加密算法,已许可登录的公钥保存在用户的 ~/.ssh/authorized_keys 文件中。


三、实现案例



1. SHA


安全散列算法(SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的几率很高。实现代码如下:

public class Main {
    public static void main(String[] args) throws Exception {
        MessageDigest sha = MessageDigest.getInstance("SHA");
        sha.update("码匠公众号".getBytes());
        System.out.println(byteToString(sha.digest()));
        MessageDigest sha224 = MessageDigest.getInstance("SHA-224");
        sha224.update("码匠公众号".getBytes());
        System.out.println(byteToString(sha224.digest()));
        MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        sha256.update("码匠公众号".getBytes());
        System.out.println(byteToString(sha256.digest()));
    }
    private static String byteToString(byte[] arr) {
        StringBuilder res = new StringBuilder();
        for (byte b : arr) {
            res.append(String.format("%02X", b));
        }
        return res.toString();
    }
}


2. MD5


MD5消息摘要算法,一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致,将数据(如一段文字)运算变为另一固定长度值,是散列算法的基础原理。代码实现如下:

public class Main {
    public static void main(String[] args) throws Exception {
        MessageDigest sha = MessageDigest.getInstance("MD5");
        sha.update("码匠公众号".getBytes());
        System.out.println(byteToString(sha.digest()));
    }
    private static String byteToString(byte[] arr) {
        ......
    }
}

MD5算法无法防止碰撞,因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。


3. DES


数据加密标准(DES)是一种对称密钥加密块密码算法,实现代码如下:

public class Main {
    public static void main(String[] args) {
        String str = "码匠公众号";
        String password = "CodeArtist";
        byte[] encrypt = encrypt(str.getBytes(), password);
        System.out.println("密文: " + byteToString(encrypt));
        byte[] decrypt = decrypt(encrypt, password);
        System.out.println("明文: " + new String(decrypt));
    }
    /**
     * 加密
     */
    public static byte[] encrypt(byte[] src, String password) {
        try {
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secureKey = keyFactory.generateSecret(desKey);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, secureKey, random);
            return cipher.doFinal(src);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 解密
     */
    public static byte[] decrypt(byte[] encrypt, String password) {
        try {
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secureKey = keyFactory.generateSecret(desKey);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, secureKey, random);
            return cipher.doFinal(encrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    private static String byteToString(byte[] arr) {
        ......
    }
}


4. AES


高级加密标准(AES)是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。实现代码如下:

public class Main {
    public static void main(String[] args) {
        String str = "码匠公众号";
        String password = "CodeArtist";
        byte[] encrypt = encrypt(str.getBytes(), password);
        System.out.println("密文: " + byteToString(encrypt));
        byte[] decrypt = decrypt(encrypt, password);
        System.out.println("明文: " + new String(decrypt));
    }
    /**
     * 加密
     */
    public static byte[] encrypt(byte[] src, String password) {
        try {
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            keygen.init(128, new SecureRandom(password.getBytes()));
            byte[] raw = keygen.generateKey().getEncoded();
            SecretKey key = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance(keygen.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(src);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 解密
     */
    private static byte[] decrypt(byte[] encrypt, String password) {
        try {
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            keygen.init(128, new SecureRandom(password.getBytes()));
            byte[] raw = keygen.generateKey().getEncoded();
            SecretKey key = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance(keygen.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(encrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    private static String byteToString(byte[] arr) {
        ......
    }
}


5. DSA


数字签名算法(DSA)是用于数字签名的联邦信息处理标准,该算法使用由公钥和私钥组成的密钥对。私钥用于生成消息的数字签名,并且可以通过使用签名者的相应公钥来验证这种签名。数字签名提供信息鉴定(接收者可以验证消息的来源),完整性(接收方可以验证消息自签名以来未被修改)和不可否认性(发送方不能错误地声称它们没有签署消息)。实现代码如下:

public class Main {
    public static void main(String[] args) throws Exception {
        String data = "码匠公众号";
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(512);
        KeyPair keypair = kpg.generateKeyPair();
        DSAPublicKey publicKey = (DSAPublicKey) keypair.getPublic();
        DSAPrivateKey privateKey = (DSAPrivateKey) keypair.getPrivate();
        Signature signature = Signature.getInstance("SHA1withDSA");
        byte[] sign = sign(signature, data.getBytes(), privateKey);
        boolean result = verify(signature, data.getBytes(), sign, publicKey);
        System.out.println(result);
    }
    /**
     * 签名
     */
    public static byte[] sign(Signature signature, byte[] data, DSAPrivateKey privateKey) {
        try {
            signature.initSign(privateKey);
            signature.update(data);
            return signature.sign();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 验证
     */
    public static boolean verify(Signature signature, byte[] data, byte[] sign, DSAPublicKey publicKey) {
        try {
            signature.initVerify(publicKey);
            signature.update(data);
            return signature.verify(sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}


6. RSA


RSA加密算法是一种非对称加密算法,在公开密钥加密和电子商业中被广泛使用。对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用RSA加密的信息的可靠性就会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式破解。到当前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被破解的。实现代码如下:

public class Main {
    public static void main(String[] args) throws Exception {
        String data = "码匠公众号";
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024);
        KeyPair keypair = kpg.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keypair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keypair.getPrivate();
        byte[] encrypt = encrypt(data.getBytes(), publicKey);
        System.out.println("密文: " + byteToString(encrypt));
        byte[] decrypt = decrypt(encrypt, privateKey);
        System.out.println("明文: " + new String(decrypt));
        System.out.println();
    }
    /**
     * 加密
     */
    public static byte[] encrypt(byte[] src, RSAPublicKey publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey.getEncoded()));
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(src);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 解密
     */
    public static byte[] decrypt(byte[] encrypt, RSAPrivateKey privateKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey.getEncoded()));
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(encrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    private static String byteToString(byte[] arr) {
        ......
    }
}


四、英文缩写对照



英文缩写 英文全拼 中文
SHA Secure Hash Algorithm 安全散列算法
MD Message Digest 信息摘要
DES Data Encryption Standard 数据加密标准
AES Advanced Encryption Standard 高级加密标准
DSA Digital Signature Algorithm 数字签名算法
RSA - 一种非对称加密算法
SSH Secure Shell 安全外壳协议
目录
相关文章
|
网络安全 Docker 容器
内网穿透访问你家里的树莓派
你有一个自己的外网服务器,然后捏你又买了一个树莓派放家里吃灰,有一天,你觉得不能让你的树莓派吃灰,你想上班的时候用你的树莓派在家里编译arm用的镜像程序。于是,便有了本篇文章~~~如何通过内网穿透访问你家里的树莓派。(注:仅用于测试,闹着玩,千万别上生产,上生产需要自己进行改造用户权限以及审计功能,这部分就不贴出来了) 使用的工具:docker,rtty,rttys
531 0
内网穿透访问你家里的树莓派
|
Python
用 Python 读取照片的 Exif 信息(顺便说说本人的一些想法)
用 Python 读取照片的 Exif 信息(顺便说说本人的一些想法)
368 2
|
11月前
|
弹性计算 应用服务中间件 定位技术
基于地理位置的访问策略的GA加速最佳实践
全球加速GA是阿里云提供的全球网络加速服务,支持基于地理位置的访问策略。本文介绍如何通过多组GA实例组合,实现一个域名在全球多个区域的服务同步加速。具体步骤包括创建ECS实例、部署Nginx服务器、配置GA及全局流量管理器等。
442 5
|
9月前
|
存储 容灾 API
云端问道19期方案教学-将本地冗余转换同城冗余,提升业务稳定性
本文介绍了阿里云对象存储OSS如何将本地冗余转换为同城冗余,以提升业务稳定性。内容分为五部分:背景介绍、存储冗余概述、创建同城冗余存储Bucket、转换Bucket的存储冗余类型及补充内容。重点讲解了本地冗余与同城冗余的区别、创建和转换同城冗余的具体操作步骤及注意事项。同城冗余能提供更高的数据持久性和服务可用性,确保业务连续性,且在转换过程中不会对业务产生影响。
220 0
|
Shell 数据安全/隐私保护 Windows
Windows Server【开机启动和任务计划程序】实现服务器重启后项目自启动(Windows Server 任务计划程序无法执行问题处理)
Windows Server【开机启动和任务计划程序】实现服务器重启后项目自启动(Windows Server 任务计划程序无法执行问题处理)
1242 0
|
机器人 开发者
钉钉机器人发送卡片消息
钉钉机器人发送卡片消息
|
Java 编译器 Linux
From Java to C++ 之内存管理篇
From Java to C++ 之内存管理篇
299 0
From Java to C++ 之内存管理篇
|
Ubuntu Linux 开发工具
RK3588安装部署openmediavault
由于 openmediavault 版本不同针对的依赖环境也不同,具体官方有说明,本次部署采用 Debian10(buster)环境下安装部署 openmediavault 5.x 版本;(官方还介绍可以基于 armbian 环境进行搭建,这是一种 ARM 平台下基于 Debian 和 Ubuntu 形成的一个 Linux 发行版)
887 0
RK3588安装部署openmediavault
|
机器学习/深度学习 计算机视觉
简单理解mAP究竟是什么
简单理解mAP究竟是什么
简单理解mAP究竟是什么
|
存储 索引
【数据结构】图的存储结构—邻接表
【数据结构】图的存储结构—邻接表
1283 0
【数据结构】图的存储结构—邻接表