㈠ md5 算法程序+详细注释,高分求教!
MD5加密算法简介
一、综述
MD5的全称是message-digest algorithm 5(信息-摘要算法),在90年代初由mit laboratory for computer science和rsa data security inc的ronald l. rivest开发出来,经md2、md3和md4发展而来。它的作用是让大容量信息在用数字签名软件签署私人密匙前被"压缩"成一种保密的格式(就是把一 个任意长度的字节串变换成一定长的大整数)。不管是md2、md4还是md5,它们都需要获得一个随机长度的信息并产生一个128位的信息摘要。虽然这些 算法的结构或多或少有些相似,但md2的设计与md4和md5完全不同,那是因为md2是为8位机器做过设计优化的,而md4和md5却是面向32位的电 脑。这三个算法的描述和c语言源代码在internet rfcs 1321中有详细的描述(http://www.ietf.org/rfc/rfc1321.txt),这是一份最权威的文档,由ronald l. rivest在1992年8月向ieft提交。
rivest在1989年开发出md2算法。在这个算法中,首先对信 息进行数据补位,使信息的字节长度是16的倍数。然后,以一个16位的检验和追加到信息末尾。并且根据这个新产生的信息计算出散列值。后来,rogier 和chauvaud发现如果忽略了检验和将产生md2冲突。md2算法的加密后结果是唯一的--既没有重复。
为了加强算法的安全性, rivest在1990年又开发出md4算法。md4算法同样需要填补信息以确保信息的字节长度加上448后能被512整除(信息字节长度mod 512 = 448)。然后,一个以64位二进制表示的信息的最初长度被添加进来。信息被处理成512位damg?rd/merkle迭代结构的区块,而且每个区块要 通过三个不同步骤的处理。den boer和bosselaers以及其他人很快的发现了攻击md4版本中第一步和第三步的漏洞。dobbertin向大家演示了如何利用一部普通的个人电 脑在几分钟内找到md4完整版本中的冲突(这个冲突实际上是一种漏洞,它将导致对不同的内容进行加密却可能得到相同的加密后结果)。毫无疑问,md4就此 被淘汰掉了。
尽管md4算法在安全上有个这么大的漏洞,但它对在其后才被开发出来的好几种信息安全加密算法的出现却有着不可忽视的引导作用。除了md5以外,其中比较有名的还有sha-1、ripe-md以及haval等。
一年以后,即1991年,rivest开发出技术上更为趋近成熟的md5算法。它在md4的基础上增加了"安全-带子"(safety-belts)的 概念。虽然md5比md4稍微慢一些,但却更为安全。这个算法很明显的由四个和md4设计有少许不同的步骤组成。在md5算法中,信息-摘要的大小和填充 的必要条件与md4完全相同。den boer和bosselaers曾发现md5算法中的假冲突(pseudo-collisions),但除此之外就没有其他被发现的加密后结果了。
van oorschot和wiener曾经考虑过一个在散列中暴力搜寻冲突的函数(brute-force hash function),而且他们猜测一个被设计专门用来搜索md5冲突的机器(这台机器在1994年的制造成本大约是一百万美元)可以平均每24天就找到一 个冲突。但单从1991年到2001年这10年间,竟没有出现替代md5算法的md6或被叫做其他什么名字的新算法这一点,我们就可以看出这个瑕疵并没有 太多的影响md5的安全性。上面所有这些都不足以成为md5的在实际应用中的问题。并且,由于md5算法的使用不需要支付任何版权费用的,所以在一般的情 况下(非绝密应用领域。但即便是应用在绝密领域内,md5也不失为一种非常优秀的中间技术),md5怎么都应该算得上是非常安全的了。
二、算法的应用
md5的典型应用是对一段信息(message)产生信息摘要(message-digest),以防止被篡改。比如,在unix下有很多软件在下载的时候都有一个文件名相同,文件扩展名为.md5的文件,在这个文件中通常只有一行文本,大致结构如:
md5 (tanajiya.tar.gz) =
这就是tanajiya.tar.gz文件的数字签名。md5将整个文件当作一个大文本信息,通过其不可逆的字符串变换算法,产生了这个唯一的md5信 息摘要。如果在以后传播这个文件的过程中,无论文件的内容发生了任何形式的改变(包括人为修改或者下载过程中线路不稳定引起的传输错误等),只要你对这个 文件重新计算md5时就会发现信息摘要不相同,由此可以确定你得到的只是一个不正确的文件。如果再有一个第三方的认证机构,用md5还可以防止文件作者的 "抵赖",这就是所谓的数字签名应用。
md5还广泛用于加密和解密技术上。比如在unix系统中用户的密码就是以md5(或其它类似的算 法)经加密后存储在文件系统中。当用户登录的时候,系统把用户输入的密码计算成md5值,然后再去和保存在文件系统中的md5值进行比较,进而确定输入的 密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这不但可以避免用户的密码被具有系统管理员权限的 用户知道,而且还在一定程度上增加了密码被破解的难度。
正是因为这个原因,现在被黑客使用最多的一种破译密码的方法就是一种被称为"跑字 典"的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用md5程序计算出这些字典项的md5值,然后 再用目标的md5值在这个字典中检索。我们假设密码的最大长度为8位字节(8 bytes),同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是p(62,1)+p(62,2)….+p (62,8),那也已经是一个很天文的数字了,存储这个字典就需要tb级的磁盘阵列,而且这种方法还有一个前提,就是能获得目标账户的密码md5值的情况 下才可以。这种加密技术被广泛的应用于unix系统中,这也是为什么unix系统比一般操作系统更为坚固一个重要原因。
三、算法描述
对md5算法简要的叙述可以为:md5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
在md5算法中,首先需要对信息进行填充,使其字节长度对512求余的结果等于448。因此,信息的字节长度(bits length)将被扩展至n*512+448,即n*64+56个字节(bytes),n为一个正整数。填充的方法如下,在信息的后面填充一个1和无数个 0,直到满足上面的条件时才停止用0对信息的填充。然后,在在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,现在的信息字 节长度=n*512+448+64=(n+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。
md5中有四个32位被称作链接变量(chaining variable)的整数参数,他们分别为:a=0x01234567,b=0x89abcdef,c=0xfedcba98,d=0x76543210。
当设置好这四个链接变量后,就开始进入算法的四轮循环运算。循环的次数是信息中512位信息分组的数目。
将上面四个链接变量复制到另外四个变量中:a到a,b到b,c到c,d到d。
主循环有四轮(md4只有三轮),每轮循环都很相似。第一轮进行16次操作。每次操作对a、b、c和d中的其中三个作一次非线性函数运算,然后将所得结 果加上第四个变量,文本的一个子分组和一个常数。再将所得结果向右环移一个不定的数,并加上a、b、c或d中之一。最后用该结果取代a、b、c或d中之 一。
以一下是每次操作中用到的四个非线性函数(每轮一个)。
f(x,y,z) =(x&y)|((~x)&z)
g(x,y,z) =(x&z)|(y&(~z))
h(x,y,z) =x^y^z
i(x,y,z)=y^(x|(~z))
(&是与,|是或,~是非,^是异或)
这四个函数的说明:如果x、y和z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。
f是一个逐位运算的函数。即,如果x,那么y,否则z。函数h是逐位奇偶操作符。
假设mj表示消息的第j个子分组(从0到15),
<< ff(a,b,c,d,mj,s,ti) 表示 a=b+((a+(f(b,c,d)+mj+ti)
<< gg(a,b,c,d,mj,s,ti) 表示 a=b+((a+(g(b,c,d)+mj+ti)
<< hh(a,b,c,d,mj,s,ti) 表示 a=b+((a+(h(b,c,d)+mj+ti)
<< ii(a,b,c,d,mj,s,ti) 表示 a=b+((a+(i(b,c,d)+mj+ti)
<< 这四轮(64步)是:
第一轮
ff(a,b,c,d,m0,7,0xd76aa478)
ff(d,a,b,c,m1,12,0xe8c7b756)
ff(c,d,a,b,m2,17,0x242070db)
ff(b,c,d,a,m3,22,0xc1bdceee)
ff(a,b,c,d,m4,7,0xf57c0faf)
ff(d,a,b,c,m5,12,0x4787c62a)
ff(c,d,a,b,m6,17,0xa8304613)
ff(b,c,d,a,m7,22,0xfd469501)
ff(a,b,c,d,m8,7,0x698098d8)
ff(d,a,b,c,m9,12,0x8b44f7af)
ff(c,d,a,b,m10,17,0xffff5bb1)
ff(b,c,d,a,m11,22,0x895cd7be)
ff(a,b,c,d,m12,7,0x6b901122)
ff(d,a,b,c,m13,12,0xfd987193)
ff(c,d,a,b,m14,17,0xa679438e)
ff(b,c,d,a,m15,22,0x49b40821)
第二轮
gg(a,b,c,d,m1,5,0xf61e2562)
gg(d,a,b,c,m6,9,0xc040b340)
gg(c,d,a,b,m11,14,0x265e5a51)
gg(b,c,d,a,m0,20,0xe9b6c7aa)
gg(a,b,c,d,m5,5,0xd62f105d)
gg(d,a,b,c,m10,9,0x02441453)
gg(c,d,a,b,m15,14,0xd8a1e681)
gg(b,c,d,a,m4,20,0xe7d3fbc8)
gg(a,b,c,d,m9,5,0x21e1cde6)
gg(d,a,b,c,m14,9,0xc33707d6)
gg(c,d,a,b,m3,14,0xf4d50d87)
gg(b,c,d,a,m8,20,0x455a14ed)
gg(a,b,c,d,m13,5,0xa9e3e905)
gg(d,a,b,c,m2,9,0xfcefa3f8)
gg(c,d,a,b,m7,14,0x676f02d9)
gg(b,c,d,a,m12,20,0x8d2a4c8a)
第三轮
hh(a,b,c,d,m5,4,0xfffa3942)
hh(d,a,b,c,m8,11,0x8771f681)
hh(c,d,a,b,m11,16,0x6d9d6122)
hh(b,c,d,a,m14,23,0xfde5380c)
hh(a,b,c,d,m1,4,0xa4beea44)
hh(d,a,b,c,m4,11,0x4bdecfa9)
hh(c,d,a,b,m7,16,0xf6bb4b60)
hh(b,c,d,a,m10,23,0xbebfbc70)
hh(a,b,c,d,m13,4,0x289b7ec6)
hh(d,a,b,c,m0,11,0xeaa127fa)
hh(c,d,a,b,m3,16,0xd4ef3085)
hh(b,c,d,a,m6,23,0x04881d05)
hh(a,b,c,d,m9,4,0xd9d4d039)
hh(d,a,b,c,m12,11,0xe6db99e5)
hh(c,d,a,b,m15,16,0x1fa27cf8)
hh(b,c,d,a,m2,23,0xc4ac5665)
第四轮
ii(a,b,c,d,m0,6,0xf4292244)
ii(d,a,b,c,m7,10,0x432aff97)
ii(c,d,a,b,m14,15,0xab9423a7)
ii(b,c,d,a,m5,21,0xfc93a039)
ii(a,b,c,d,m12,6,0x655b59c3)
ii(d,a,b,c,m3,10,0x8f0ccc92)
ii(c,d,a,b,m10,15,0xffeff47d)
ii(b,c,d,a,m1,21,0x85845dd1)
ii(a,b,c,d,m8,6,0x6fa87e4f)
ii(d,a,b,c,m15,10,0xfe2ce6e0)
ii(c,d,a,b,m6,15,0xa3014314)
ii(b,c,d,a,m13,21,0x4e0811a1)
ii(a,b,c,d,m4,6,0xf7537e82)
ii(d,a,b,c,m11,10,0xbd3af235)
ii(c,d,a,b,m2,15,0x2ad7d2bb)
ii(b,c,d,a,m9,21,0xeb86d391)
常数ti可以如下选择:
在第i步中,ti是4294967296*abs(sin(i))的整数部分,i的单位是弧度。(4294967296等于2的32次方)
所有这些完成之后,将a、b、c、d分别加上a、b、c、d。然后用下一分组数据继续运行算法,最后的输出是a、b、c和d的级联。
当你按照我上面所说的方法实现md5算法以后,你可以用以下几个信息对你做出来的程序作一个简单的测试,看看程序有没有错误。
md5 ("") =
md5 ("a") =
md5 ("abc") =
md5 ("message digest") =
md5 ("abcdefghijklmnopqrstuvwxyz") =
md5 ("") =
md5 ("1234567890") =
如果你用上面的信息分别对你做的md5算法实例做测试,最后得出的结论和标准答案完全一样,那我就要在这里象你道一声祝贺了。要知道,我的程序在第一次编译成功的时候是没有得出和上面相同的结果的。
四、MD5的安全性
md5相对md4所作的改进:
1. 增加了第四轮;
2. 每一步均有唯一的加法常数;
3. 为减弱第二轮中函数g的对称性从(x&y)|(x&z)|(y&z)变为(x&z)|(y&(~z));
4. 第一步加上了上一步的结果,这将引起更快的雪崩效应;
5. 改变了第二轮和第三轮中访问消息子分组的次序,使其更不相似;
6. 近似优化了每一轮中的循环左移位移量以实现更快的雪崩效应。各轮的位移量互不相同。
㈡ java.awt的类摘要
AlphaComposite AlphaComposite 类实现一些基本的 alpha 合成规则,将源色与目标色组合,在图形和图像中实现混合和透明效果。 AWTEvent 所有 AWT 事件的根事件类。 AWTEventMulticaster AWTEventMulticaster 实现对 java.awt.event 包中定义的 AWT 事件的指派,该指派是有效的、线程安全的多路广播事件指派。 AWTKeyStroke AWTKeyStroke 表示键盘(或等效输入设备)上的键操作。 AWTPermission 此类用于 AWT 权限。 BasicStroke BasicStroke 类定义针对图形图元轮廓呈现属性的一个基本集合,这些图元使用Graphics2D对象呈现,而该对象的 Stroke 属性设置为此 BasicStroke。 BorderLayout 这是一个布置容器的边框布局,它可以对容器组件进行安排,并调整其大小,使其符合下列五个区域:北、南、东、西、中。 BufferCapabilities 缓冲区的能力和属性。 BufferCapabilities.FlipContents 页面翻转后可能的后台缓冲区内容的一个类型安全的枚举 Button 此类创建一个标签按钮。 Canvas Canvas 组件表示屏幕上一个空白矩形区域,应用程序可以在该区域内绘图,或者可以从该区域捕获用户的输入事件。 CardLayout CardLayout 对象是容器的布局管理器。 Checkbox 复选框是一个可处于“开”(true) 或“关”(false) 状态的图形组件。 CheckboxGroup CheckboxGroup 类用于集合 Checkbox 按钮集。 CheckboxMenuItem 此类表示一个可包括在菜单中的复选框。 Choice Choice 类表示一个弹出式选择菜单。 Color Color 类用于封装默认 sRGB 颜色空间中的颜色,或者用于封装由ColorSpace标识的任意颜色空间中的颜色。 Component component是一个具有图形表示能力的对象,可在屏幕上显示,并可与用户进行交互。 ComponentOrientation ComponentOrientation 类封装语言敏感的方向,用于排序组件或文本内容。 Container 一般的 Abstract Window Toolkit(AWT) 容器对象是一个可包含其他 AWT 组件的组件。 Cursor 封装鼠标光标的位图表示形式的类。 DefaultKeyboardFocusManager AWT 应用程序的默认 KeyboardFocusManager。 Desktop Desktop 类允许 Java 应用程序启动已在本机桌面上注册的关联应用程序,以处理URI或文件。 Dialog Dialog 是一个带标题和边界的顶层窗口,边界一般用于从用户处获得某种形式的输入。 Dimension Dimension 类封装单个对象中组件的宽度和高度(精确到整数)。 DisplayMode DisplayMode 类封装 GraphicsDevice 的位深、高度、宽度和刷新率。 Event 注:Event 类已废弃,只可用于向后兼容。 EventQueue EventQueue 是一个与平台无关的类,它将来自于底层同位体类和受信任的应用程序类的事件列入队列。 FileDialog FileDialog 类显示一个对话框窗口,用户可以从中选择文件。 FlowLayout 流布局用于安排有向流中的组件,这非常类似于段落中的文本行。 FocusTraversalPolicy FocusTraversalPolicy 定义一种顺序,按此顺序遍历具有特定焦点循环根的 Component。 Font Font 类表示字体,可以使用它以可见方式呈现文本。 FontMetrics FontMetrics 类定义字体规格对象,该对象封装将在特定屏幕上呈现特定字体的有关信息。 Frame Frame 是带有标题和边框的顶层窗口。 GradientPaint GradientPaint 类提供了使用线性颜色渐变模式填充Shape的方法。 Graphics Graphics 类是所有图形上下文的抽象基类,允许应用程序在组件(已经在各种设备上实现)以及闭屏图像上进行绘制。 Graphics2D 此 Graphics2D 类扩展Graphics类,以提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制。 GraphicsConfigTemplate GraphicsConfigTemplate 类用于获得有效的GraphicsConfiguration。 GraphicsConfiguration GraphicsConfiguration 类描述图形目标(如打印机或监视器)的特征。 GraphicsDevice GraphicsDevice 类描述可以在特定图形环境中使用的图形设备。 GraphicsEnvironment GraphicsEnvironment 类描述了 Java(tm) 应用程序在特定平台上可用的GraphicsDevice对象和Font对象的集合。 GridBagConstraints GridBagConstraints 类指定使用 GridBagLayout 类布置的组件的约束。 GridBagLayout GridBagLayout 类是一个灵活的布局管理器,它不要求组件的大小相同便可以将组件垂直、水平或沿它们的基线对齐。 GridBagLayoutInfo GridBagLayoutInfo 是 GridBagLayout 布局管理器的一个实用工具类。 GridLayout GridLayout 类是一个布局处理器,它以矩形网格形式对容器的组件进行布置。 Image 抽象类 Image 是表示图形图像的所有类的超类。 ImageCapabilities 图像的功能和属性。 Insets Insets 对象是容器边界的表示形式。 JobAttributes 控制打印作业的属性集合。 JobAttributes.DefaultSelectionType 可能的默认选择状态的类型安全的枚举。 JobAttributes.DestinationType 可能的作业目标的类型安全枚举。 JobAttributes.DialogType 显示给用户的可能对话框的类型安全枚举。 JobAttributes.MultipleDocumentHandlingType 可能的多副本处理状态的类型安全枚举。 JobAttributes.SidesType 可能的多页整版的类型安全枚举。 KeyboardFocusManager KeyboardFocusManager 负责管理激活状态的聚焦 Window 和当前焦点所有者。 Label Label 对象是一个可在容器中放置文本的组件。 LinearGradientPaint LinearGradientPaint 类提供利用线性颜色渐变模式填充Shape的方式。 List List 组件为用户提供了一个可滚动的文本项列表。 MediaTracker MediaTracker 类是一个跟踪多种媒体对象状态的实用工具类。 Menu Menu 对象是从菜单栏部署的下拉式菜单组件。 MenuBar MenuBar 类封装绑定到框架的菜单栏的平台概念。 MenuComponent 抽象类 MenuComponent 是所有与菜单相关的组件的超类。 MenuItem 菜单中的所有项必须属于类 MenuItem 或其子类之一。 MenuShortcut 表示 MenuItem 键盘加速器的 MenuShortcut 类。 MouseInfo MouseInfo 提供获取有关鼠标信息的方法,如鼠标指针位置和鼠标按钮数。 MultipleGradientPaint 这是 Paints 的超类,它使用多个颜色渐变来填充它们的光栅。 PageAttributes 用来控制打印页面输出的属性集。 PageAttributes.ColorType 可能颜色状态的类型安全的枚举。 PageAttributes.MediaType 可能的纸张大小的类型安全的枚举。 PageAttributes.OrientationRequestedType 可能打印方向的类型安全的枚举。 PageAttributes.OriginType 可能原点的类型安全的枚举。 PageAttributes.PrintQualityType 可能的打印质量的类型安全的枚举。 Panel Panel 是最简单的容器类。 Point 表示 (x,y) 坐标空间中的位置的点,以整数精度指定。 PointerInfo 描述指针位置的类。 Polygon Polygon 类封装了坐标空间中封闭的二维区域的描述。 PopupMenu 此类实现能够在组件中的指定位置上动态弹出的菜单。 PrintJob 启动并执行打印作业的抽象类。 RadialGradientPaint RadialGradientPaint 类提供使用圆形辐射颜色渐变模式填充某一形状的方式。 Rectangle Rectangle 指定坐标空间中的一个区域,通过坐标空间中 Rectangle 对象左上方的点 (x,y)、宽度和高度可以定义这个区域。 RenderingHints RenderingHints 类定义和管理键和关联值的集合,它允许应用程序将输入提供给其他类使用的算法选择,这些类执行呈现和图像处理服务。 RenderingHints.Key 定义与RenderingHints一起使用的、用来控制呈现和图像管线中各种算法选择的所有键的基本类型。 Robot 此类用于为测试自动化、自运行演示程序和其他需要控制鼠标和键盘的应用程序生成本机系统输入事件。 Scrollbar Scrollbar 类描述了一个滚动条,这是大家都很熟悉的用户界面对象。 ScrollPane 实现用于单个子组件的自动水平和/或垂直滚动的容器类。 ScrollPaneAdjustable 此类表示 ScrollPane 的水平或垂直滚动条的状态。 SplashScreen 在 Java 虚拟机 (JVM) 启动之前,可以在应用程序启动时创建闪现屏幕。 SystemColor 封装表示系统中本机 GUI 对象颜色的象征性颜色的类。 SystemTray SystemTray 类表示桌面的系统托盘。 TextArea TextArea 对象是显示文本的多行区域。 TextComponent TextComponent 类是所有允许编辑文本的组件的超类。 TextField TextField 对象是允许编辑单行文本的文本组件。 TexturePaint TexturePaint 类提供一种用被指定为BufferedImage的纹理填充Shape的方式。 Toolkit 此类是所有 Abstract Window Toolkit 实际实现的抽象超类。 TrayIcon TrayIcon 对象表示可以添加到系统托盘的托盘图标。 Window Window 对象是一个没有边界和菜单栏的顶层窗口。
㈢ springboot添加依赖(springboot添加依赖报错)
SpringBootWeb项目依赖分析在上篇中,我们得到如下的pom.xml
看看其核心类容:
按住ctrl并点击parent中spring-boot-stater-parent节点,可以看到
spring-boot-stater-parent有一个parentspring-boot-dependencies
根据名字分析,是spring-boot项目依赖的
继续点击spring-boot-dependencies
可以看到其在properties中配置了大量的依赖版本
我当前这个版本(2.2.3.RELEASE)在properties中共配置了203个依赖的版本
properties下面dependencyManagement节点中,配置了依赖组建的版本:
在项目的pom.xml中查看依赖树:
可以看到springboot-starter-web添加了tomcat,web,webmvc,spring-core,spring-context等依赖
这也就是为什么我们可以直接通过DemoApplication.main来运行,而不需要配置外部servlet容器的原因,同时,通过这个starter-web就已经将web相关的依赖都整合进来了。
springboot中提供了很多starter,比如
springBoot必用依赖框架使用Lombok框架
在编写POJO类型(包括实体类、VO、DTO等)时,都有统一的编码规范,例如:
由于以上操作方式非常固定,且涉及的代码量虽然不难,但是篇幅较长,并且,当类中的属性需要修改时(包括修改原有属性、或增加新属性、删除原有属性),对应的其它方法都需要修改(或重新生成),管理起来比较麻烦。
在SpringBoot中,添加Lombok依赖,可以在创建项目时勾选,也可以后期自行添加,依赖项的代码为:
完成后,在各POJO类型中,将不再需要在源代码添加SettersGetters、`equals()`、`hashCode()`、`toString()`这些方法,只需要在POJO类上添加`@Data`注解即可!
当添加`@Data`注解,且删除相关方法后,由于源代码中没有相关方法,则调用了相关代码的方法可能会报错,但是,并不影响程序运行!
为了避免IntelliJIDEA判断失误而提示了警告和错误,推荐安装Lombok插件,可参考:
【注】:无论是否安装插件,都不影响代码的编写和运行!
Slf4j日志框架
在开发实践中,不允许使用`System.out.println()`或类似的输出语句来输出显示关键数据(核心数据、敏感数据等),因为,如果是这样使用,无论是在开发环境,还是测试环境,还是生产环境中,这些输出语句都将输出相关信息,而删除或添加这些输出语句的操作成本比较高,操作可行性低。
推荐的做法是使用日志框架来输出相关信息!
在Slf4j日志框架中,将日志的可显示级别根据其重要程度(严重程度)由低到高分为:
在配置文件中,可以通过`logging.level.包名.类名`来设置当前类的日志显示级别,例如:
当设置了显示的日志级别后,仅显示设置级别和更重要的级别的日志,例如,设置为`info`时,只显示`info`、`warn`、`error`,不会显示`debug`、`trace`级别的日志!
当输出日志时,通过`log`变量调用`trace()`方法输出的日志就是`trace`级别的,调用`debug()`方法输出的日志就是`debug()`级别的,以此类推,可调用的方法还有`info()`、`warn()`、`error()`。
在开发实践中,关键数据和敏感数据都应该通过`trace()`或`debug()`进行输出,在开发环境中,可以将日志的显示级别设置为`trace`,则会显示所有日志,当需要交付到生产环境中时,只需要将日志的显示级别调整为`info`即可!
默认情况下,日志的显示级别是`info`,所以,即使没有在配置文件中进行正确的配置,所有info、warn、error级别的日志都会输出显示。
在使用Slf4j时,通过`log`调用的每种级别的方法都被重载了多次(各级别对应除了方法名称不同,重载的次数和参数列表均相同),推荐使用的方法是参数列表为`(Stringformat,Object...arguments)`的,例如:
以上方法中,第1个参数是将要输出的字符串的模式(模版),在此字符串中,如果需要包含某个变量值,则使用`{}`表示,如果有多个变量值,均是如此,然后,再通过第2个参数(是可变参数)依次表示各`{}`对应的值,例如:
使用这种做法,可以避免多变量时频繁的拼接字符串,另外,日志框架会将第1个参数进行缓存,以此提高后续每一次的执行效率。
在开发实践中,应该对程序执行关键位置添加日志的输出,通常包括:
其实,Slf4j日志框架只是日志的一种标准,并不是具体的实现(感觉上与Java中的接口有点相似),常见有具体实现了日志功能的框架有log4j、logback等,为了统一标准,所以才出现了Slf4j,同时,由于log4j、logback等框架实现功能并不统一,所以,Slf4j提供了对主流日志框架的兼容,在SpringBoot工程中,`spring-boot-starter`就已经依赖了`spring-boot-starter-logging`,而在此依赖下,通常包括Slf4j、具体的日志框架、Slf4j对具体日志框架的兼容。
密码加密(额外知识点)
【这并不是SpringBoot框架的知识点】
对密码进行加密,可以有效的保障密码安全,即使出现数据库泄密,密码安全也不会受到影响!为了实现此目标,需要在对密码进行加密时,使用不可逆的算法进行处理!
通常,不可以使用加密算法对密码进行加密码处理,从严格定义上来看,所有的加密算法都是可以逆向运算的,即同时存在加密和解密这2种操作,加密算法只能用于保证传输过程的安全,并不应该用于保证需要存储下来的密码的安全!
哈希算法都是不可逆的,通常,用于处理密码加密的算法中,典型的是一些消息摘要算法,例如MD5、SHA256或以上位数的算法。
消息摘要算法的主要特征有:
在消息摘要算法中,以MD5为例,其运算结果是一个128位长度的二进制数,通常会转换成十六进制数显示,所以是32位长度的十六进制数,MD5也被称之为128位算法。理论上,会存在2的128次方种类的摘要结果,且对应2的128次方种不同的消息,如果在未超过2的128次方种消息中,存在2个或多个不同的消息对应了相同的摘要,则称之为:发生了碰撞。一个消息摘要算法是否安全,取决其实际的碰撞概率,关于消息摘要算法的破解,也是研究其碰撞概率。
存在穷举消息和摘要的对应关系,并利用摘要在此对应关系进行查询,从而得知消息的做法,但是,由于MD5是128位算法,全部穷举是不可能实现的,所以,只要原始密码(消息)足够复杂,就不会被收录到所记录的对应关系中去!
为了进一步提高密码的安全性,在使用消息摘要算法进行处理时,通常还会加盐!盐值可以是任意的字符串,用于与密码一起作为被消息摘要算法运算的数据即可,例如:
加盐的目的是使得被运算数据变得更加复杂,盐值本身和用法并没有明确要求!
甚至,在某些用法或算法中,还会使用随机的盐值,则可以使用完全相同的原消息对应的摘要却不同!
推荐了解:预计算的哈希链、彩虹表、雪花算法。
为了进一步保证密码安全,还可以使用多重加密,即反复调用消息摘要算法。
除此以外,还可以使用安全系数更高的算法,例如SHA-256是256位算法,SHA-384是384位算法,SHA-512是512位算法。
Validation框架
当客户端向服务器提交请求时,如果请求数据出现明显的问题(例如关键数据为`null`、字符串的长度不在可接受范围内、其它格式错误),应该直接响应错误,而不是将明显错误的请求参数传递到Service!
关于判断错误,只有涉及数据库中的数据才能判断出结果的,都由Service进行判断,而基本的格式判断,都由Controller进行判断。
Validation框架是专门用于解决检查数据基本格式有效性的,最早并不是Spring系列的框架,目前,SpringBoot提供了更好的支持,所以,通常结合在一起使用。
在SpringBoot项目中,需要添加`spring-boot-starter-validation`依赖项,例如:
在控制器中,首先,对需要检查数据格式的请求参数添加`@Valid`或`@Validated`注解(这2个注解没有区别),例如:
真正需要检查的是`AdminAddNewDTO`中各属性的值,所以,接下来需要在此类的各属性上通过注解来配置检查的规则,例如:
重启项目,通过不提交用户名的URL(例如:)进行访问,在浏览器上会出现400错误页面,并且,在IntelliJIDEA的控制台会出现以下警告:
从警告信息中可以看到,当验证失败时(不符合所使用的注解对应的规则时),会出现`org.springframework.validation.BindException`异常,则自行处理此异常即可!
首先,在`State`中添加新的枚举:
然后,在`GlobalExceptionHandler`中添加新的处理异常的方法:
关于错误提示信息,以上内容中出现了`不能为null`的字样,是默认的提示文本,可以通过`@NotNull`注解的`message`属性进行配置,例如:
然后,在处理异常时,通过异常信息获取自定义的提示文本:
再次运行,在不提交用户名和密码的情况下,会随机的提示用户名或密码验证失败的提示文本中的某1条。
在Validation框架中,还有其它许多注解,用于进行不同格式的验证,例如:
以上注解,包括`@NotNull`是允许叠加使用的,即允许在同一个参数属性上添加多个注解!
以上注解均可以配置`message`属性,用于指定验证失败的提示文本。
通常:(开发中)
Springboot动态的配置Scheling一:springboot配置静态定时任务
1:pom中添加依赖
2:启动类中加入@EnableScheling来开启定时任务
3:@Scheled(cron=?"0/10****?")//每过10秒执行一次
二:?springboot动态配置定时任务:主要动态的配置。
packagecom.example.demo.config;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.lang.Nullable;
importorg.springframework.scheling.Trigger;
importorg.springframework.scheling.TriggerContext;
importorg.springframework.scheling.concurrent.ThreadPoolTaskScheler;
importorg.springframework.scheling.support.CronTrigger;
importorg.springframework.stereotype.Component;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjava.util.concurrent.ScheledFuture;
@Component
@Configuration
{
@Autowired
??;
??@Bean
??(){
();
??}
privateScheledFuturefuture;
??privateStringcron="";
??publicStringgetCron(){
returncron;
??}
publicvoidsetCron(Stringcron){
this.cron=cron;
????stopCron();
????future=threadPoolTaskScheler.schele(newRunnable(){
@Override
???????publicvoidrun(){
try{
System.out.println(newSimpleDateFormat("yyyy-MM-ddHH:mm:ss").format(newDate()));
?????????}catch(Exceptione){
e.printStackTrace();
?????????}
}
},newTrigger(){
@Nullable
@Override
???????publicDatenextExecutionTime(TriggerContexttriggerContext){
if("".equals(cron)||cron==null){
returnnull;
?????????}
CronTriggercronTrigger=newCronTrigger(cron);
?????????DatenextExeDate=cronTrigger.nextExecutionTime(triggerContext);
?????????returnnextExeDate;
???????}
});
??}
publicvoidstopCron(){
if(future!=null){
future.cancel(true);
????}
}
}
关于springboot如何添加其他依赖spring?boot?基本依赖
1.基础核心依赖
parent
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-parent/artifactId????version1.5.1.RELEASE/version
/parent
2.web应用依赖
dependencies
dependency
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-web/artifactId
/dependency
/dependencies
3.使用freemark依赖(不和web应用依赖共存)
dependencies
dependency
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-freemarker/artifactId
/dependency
/dependencies
扩充一下:
㈣ 开发中常见的加密方式及应用
开发中常见的加密方式及应用
一、base64
简述:Base64是网络上最常见的用于传输8Bit 字节码 的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。所有的数据都能被编码为并只用65个字符就能表示的文本文件。( 65字符:A~Z a~z 0~9 + / = )编码后的数据~=编码前数据的4/3,会大1/3左右(图片转化为base64格式会比原图大一些)。
应用:Base64编码是从二进制到字符的过程,可用于在 HTTP 环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一 标识符 (一般为128-bit的UUID)编码为一个字符串,用作HTTP 表单 和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制 数据编码 为适合放在URL(包括隐藏 表单域 )中的形式。此时,采用Base64编码具有不可读性,需要解码后才能阅读。
命令行进行Base64编码和解码
编码:base64 123.png -o 123.txt
解码:base64 123.txt -o test.png -D Base64编码的原理
原理:
1)将所有字符转化为ASCII码;
2)将ASCII码转化为8位二进制;
3)将二进制3个归成一组(不足3个在后边补0)共24位,再拆分成4组,每组6位;
4)统一在6位二进制前补两个0凑足8位;
5)将补0后的二进制转为十进制;
6)从Base64编码表获取十进制对应的Base64编码;
Base64编码的说明:
a.转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。
b.数据不足3byte的话,于缓冲区中剩下的bit用0补足。然后,每次取出6个bit,按照其值选择查表选择对应的字符作为编码后的输出。
c.不断进行,直到全部输入数据转换完成。
d.如果最后剩下两个输入数据,在编码结果后加1个“=”;
e.如果最后剩下一个输入数据,编码结果后加2个“=”;
f.如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。
二、HASH加密/单向散列函数
简述:Hash算法特别的地方在于它是一种单向算法,用户可以通过Hash算法对目标信息生成一段特定长度(32个字符)的唯一的Hash值,却不能通过这个Hash值重新获得目标信息。对用相同数据,加密之后的密文相同。 常见的Hash算法有MD5和SHA。由于加密结果固定,所以基本上原始的哈希加密已经不再安全,于是衍生出了加盐的方式。加盐:先对原始数据拼接固定的字符串再进行MD5加密。
特点:
1) 加密 后密文的长度是定长(32个字符的密文)的
2)如果明文不一样,那么散列后的结果一定不一样
3)如果明文一样,那么加密后的密文一定一样(对相同数据加密,加密后的密文一样)
4)所有的加密算法是公开的
5)不可以逆推反算(不能根据密文推算出明文),但是可以暴力 破解 ,碰撞监测
原理:MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要。
1)数据填充
对消息进行数据填充,使消息的长度对512取模得448,设消息长度为X,即满足X mod 512=448。根据此公式得出需要填充的数据长度。
填充方法:在消息后面进行填充,填充第一位为1,其余为0。
2)添加信息长度
在第一步结果之后再填充上原消息的长度,可用来进行的存储长度为64位。如果消息长度大于264,则只使用其低64位的值,即(消息长度 对264取模)。
在此步骤进行完毕后,最终消息长度就是512的整数倍。
3)数据处理
准备需要用到的数据:
4个常数:A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;
4个函数:F(X,Y,Z)=(X & Y) | ((~X) & Z);G(X,Y,Z)=(X & Z) | (Y & (~Z));H(X,Y,Z)=X ^ Y ^ Z;I(X,Y,Z)=Y ^ (X | (~Z));
把消息分以512位为一分组进行处理,每一个分组进行4轮变换,以上面所说4个常数为起始变量进行计算,重新输出4个变量,以这4个变量再进行下一分组的运算,如果已经是最后一个分组,则这4个变量为最后的结果,即MD5值。
三、对称加密
经典算法:
1)DES数据加密标准
DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。
DES算法是这样工作的:如Mode为加密,则用Key去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。
2)3DES使用3个密钥,对消息进行(密钥1·加密)+(密钥2·解密)+(密钥3·加密)
3)AES高级加密标准
如图,加密/解密使用相同的密码,并且是可逆的
四、非对称加密
特点:
1)使用公钥加密,使用私钥解密
2)公钥是公开的,私钥保密
3)加密处理安全,但是性能极差
经典算法RSA:
1)RSA原理
(1)求N,准备两个质数p和q,N = p x q
(2)求L,L是p-1和q-1的最小公倍数。L = lcm(p-1,q-1)
(3)求E,E和L的最大公约数为1(E和L互质)
(4)求D,E x D mode L = 1
五、数字签名
原理以及应用场景:
1)数字签名的应用场景
需要严格验证发送方身份信息情况
2)数字签名原理
(1)客户端处理
对"消息"进行HASH得到"消息摘要"
发送方使用自己的私钥对"消息摘要"加密(数字签名)
把数字签名附着在"报文"的末尾一起发送给接收方
(2)服务端处理
对"消息" HASH得到"报文摘要"
使用公钥对"数字签名"解密
对结果进行匹配
六、数字证书
简单说明:
证书和驾照很相似,里面记有姓名、组织、地址等个人信息,以及属于此人的公钥,并有认证机构施加数字签名,只要看到公钥证书,我们就可以知道认证机构认证该公钥的确属于此人。
数字证书的内容:
1)公钥
2)认证机构的数字签名
证书的生成步骤:
1)生成私钥openssl genrsa -out private.pem 1024
2)创建证书请求openssl req -new -key private.pem -out rsacert.csr
3)生成证书并签名,有效期10年openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
4)将PEM格式文件转换成DER格式openssl x509 -outform der -in rsacert.crt -out rsacert.der
5)导出P12文件openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
iOS开发中的注意点:
1)在iOS开发中,不能直接使用PEM格式的证书,因为其内部进行了Base64编码,应该使用的是DER的证书,是二进制格式的;
2)OpenSSL默认生成的都是PEM格式的证书。
七、https
HTTPS和HTTP的区别:
超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息。HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此HTTP协议不适合传输一些敏感信息,比如信用卡号、密码等。
为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS。为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
HTTPS和HTTP的区别主要为以下四点:
1)https协议需要到ca申请证书,一般免费证书很少,需要交费。
2)http是 超文本传输协议 ,信息是明文传输,https则是具有 安全性 的 ssl 加密传输协议。
3)http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4)http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的 网络协议 ,比http协议安全。
5)SSL:Secure Sockets Layer安全套接字层;用数据加密(Encryption)技术,可确保数据在网络上传输过程中不会被截取及窃听。目前一般通用之规格为40 bit之安全标准,美国则已推出128 bit之更高安全标准,但限制出境。只要3.0版本以上之I.E.或Netscape 浏览器 即可支持SSL。目前版本为3.0。SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层:SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。