大家好,我是吴师兄。
最近发生的一系列事件让我越来越坚信,
世界果然都是一个草台班子
。
无论是游戏、股票市场,还是顶尖科技公司,大家所仰望的那些“大牌”,实际上也经常暴露出让人啼笑皆非的问题。这不仅让我开始反思:
我们是否过度神话了那些所谓的巨头
?
举个例子,国服《炉石传说》刚回归,大家都满怀期待,结果服务器却频繁崩溃,官方给出的理由竟然是“
玩家人数太多,底层服务器承受不住,出现了意想不到的 bug
”。
这就像你去参加一场高规格的晚宴,结果主办方居然没有足够的餐具。
就连道歉的过程还是高高在上的姿态。
再看 A 股市场,最近因为行情火热,上交所的系统甚至被挤爆,连这样关键的基础设施在高压之下也会出现问题。
而更令人惊讶的是,Meta(也就是之前的Facebook)居然和 CSDN 一样,曾经明文存储用户密码。作为全球科技巨头,这种低级错误让人不禁怀疑,连他们都不例外吗?
这些例子让我不得不开始质疑我们对大型公司的技术水平的期待。
无论是游戏公司、金融市场,还是科技巨头,都没有我们想象中的那么完美。或许,每一个行业的背后,都藏着我们看不到的“草台班子”运作。
漏洞不仅仅存在,而且往往出现在我们最意想不到的地方。
因此,越来越多的人,包括我自己,开始接受一个现实:
世界并非是一个完美的体系,无论规模多大、技术多先进的公司,背后也有着这样那样的隐患
。
我们常常认为,像 Meta 这样的科技巨头在用户数据保护上一定是高标准,但现实却一次次打破这种神话。当我们回顾这些事件时,发现很多时候我们对技术的认知存在误区,甚至连一些基础概念都被误解和滥用。
其中一个典型的例子就是 MD5 。
MD5往往被很多人误认为是一种“加密算法”,但实际上它并不具备真正的加密功能。
MD5的原本设计是用于数据的完整性校验,也就是说,它的主要功能是将一段数据通过算法转换为一串固定长度的哈希值,用来确认数据是否被篡改。
然而,随着时间的推移,MD5逐渐被滥用于加密场景,但这显然是不合适的。尤其是在互联网和信息安全领域,MD5的安全性已经被证明不再可靠,原因就在于它容易被破解或碰撞攻击。
然而令人意外的是,很多公司仍在使用MD5,甚至是以“加密”的方式进行用户密码的存储,这无疑是一种技术滥用和误解。
正如前面提到的那些漏洞一样,巨头公司表面看起来无懈可击,但实际上也会因为技术上的疏忽或误解,导致安全隐患。
尤其是当我们谈论“加密”时,更需要明确知道什么是安全的,什么是已经过时的。
接下来,我想简单聊一聊,为什么MD5不能算作加密算法,它和真正的加密算法之间到底有哪些本质区别。
一、MD5算法
MD5
即 Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一,主流编程语言普遍已有
MD5
实现。
将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,
MD5
的前身有 MD2 、MD3 和 MD4 。
MD5
是输入不定长度信息,输出固定长度 128-bits 的算法。经过程序流程,生成四个32位数据,最后联合起来成为一个 128-bits 散列。
基本方式为,求余、取余、调整长度、与链接变量进行循环运算,得出结果。
MD5
计算广泛应用于错误检查。在一些 BitTorrent 下载中,软件通过计算 MD5 来检验下载到的碎片的完整性。
二、加密算法
百度百科
:加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容。
维基百科
:在密码学中,
加密
(英语:Encryption)是将明文信息改变为难以读取的密文内容,使之不可读的过程。只有拥有解密方法的对象,经由解密过程,才能将密文还原为正常可读的内容。
三、对比
也就是说,MD5 算法和加密算法都可以将信息转换为另外一种内容。
但是,
MD5 算法
对比
加密算法
缺少了解密过程。
事实上,使用
加密算法
加密后的消息是完整的,并且基于解密算法后,可以恢复原始数据。
而
MD5 算法
得到的消息是不完整的,并且通过摘要的数据也无法得到原始数据。
所以,
MD5 算法不是加密算法
!
...
回归我们公众号的主题。
继续来一道和「大厂秋招」相关的算法原题。
题目描述
给定一段"密文"字符串
s
,其中字符都是经过"密码本"映射的,现需要将"密文"解密并且输出。
映射的规则 :
"a-i"
分别用
"1-9"
表示,
"j-z"
分别用
"10*-26*"
表示
约束:映射始终唯一
输入描述
“密文”字符串
输出描述
明文字符串
补充说明
翻译后的文本的长度在
100
以内
示例一
输入
20*19*20*
输出
tst
示例二
输入
12320*12319*20*
输出
abctabcst
解题思路
本题需要分两步走:对原字符串的预处理以及元素映射关系。
元素映射
涉及元素一一映射的关系,构建从数字到字母的映射这件事,
很容易想到应该使用哈希表来解决
。
为了构建数字和字母之间的映射,可以使用ASCII码值来完成。使用
ord("a")
可以计算得到字符
"a"
的ASCII码值,选定数字
i
的范围为
[1, 26]
,则
ord("a")+i-1
可以得到所有小写字母的ASCII码值,再使用
chr()
内置函数将ASCII码值转换回小写字母,即
chr(ord("a")+i-1)
。故构建映射关系哈希表的代码为
dic = {str(i): chr(ord("a") + i - 1) for i in range(1, 27)}
两位数的处理
另外,本题所给密码字符串中,两位数(
10-26
)的后面都会带一个
*
,而一位数(
1-9
)的后面不带
*
,我们必须把这两种情况区分开来。
如果我们从头到尾地遍历原字符串
s
,每次遇到一个
*
号,则说明此时
*
号前面的两个字符需要合并在一起,视为一个两位数来处理。
很显然,只有在遇到
*
号的时候,才需要去查看刚刚
最新遇到的两个数字字符
,这是一种后进先出的思路,很显然可以使用栈来处理这个过程。其过程如下
stack = list()
for ch in s:
if ch == "*":
digit_1 = stack.pop()
digit_10 = stack.pop()
stack.append(digit_10 + digit_1)
else:
stack.append(ch)
退出循环后,栈中储存了若干个数字字符串(有一位数也有两位数),再将这些数字字符串传入哈希表中进行从数字到字母的映射,再合并为一个字符串输出即为答案。代码如下
print("".join(dic[num_str] for num_str in stack))
代码
Python
# 关注吴师兄,算法学习好轻松
# 构建数字和字母之间的映射关系
dic = {str(i): chr(ord("a") + i - 1) for i in range(1, 27)}
# 输入字符串
s = input()
# 构建一个栈
stack = list()
# 遍历s中所有字符
for ch in s:
# 如果是*号,说明*前面的两个数字要合并为一个两位数一起考虑
if ch == "*":
# 弹出栈顶两个元素,分别是个位和十位的字符串
# 先弹出个位,再弹出10位
digit_1 = stack.pop()
digit_10 = stack.pop()
# 将合并后的两位数重新压回栈顶
stack.append(digit_10 + digit_1)
# 如果不是*号,而是数字,则直接入栈
else:
stack.append(ch)
# 最后栈中的所有元素即为数字字符串,使用dic进行从数字到字母的映射之后再合并即可
print("".join(dic[num_str] for num_str in stack))
Java
import java.util.HashMap;
import java.util.Scanner;
import java.util.Stack;
public