Long Luo's Life Notes

每一天都是奇迹

By Long Luo

一、RSA 是什么?

\(\textit{RSA}\) 1公钥加密算法是1977年由Ron Rivest、Adi Shamirh和Leonard Adleman在(美国麻省理工学院)开发的。\(\textit{RSA}\) 取名来自开发他们三者的名字。

\(\textit{RSA}\) 算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

二、RSA算法原理

\(\textit{RSA}\) 算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。

下面我们就详细讲解下 \(\textit{RSA}\) 算法加解密过程。

2.1 RSA算法组成部分

  • 原文(Message):需要加密的信息,可以是数字、文字、视频、音频等,用 \(M\) 表示。
  • 密文(Ciphertext):加密后得到的信息,用 \(C\) 表示。
  • 公钥(Public Key)和私钥(Private Key):用 \(PU\)\(PR\) 表示。
  • 加密算法(Encryption):若 \(E(x)\) 为加密算法,加密过程可以理解为 \(C = E(M)\) 根据原文和加密算法得到密文。
  • 解密算法(Decryption):若 \(D(x)\) 为解密算法,解密过程可以理解为 \(M=D(C)\) 根据密文和解密算法得到原文。

2.2 RSA算法加密过程

  1. 随机选择两个不相同的素数 \(p, q\)
  2. \(p, q\) 相乘,记为 \(n = p \times q\)
  3. 计算 \(n\) 的欧拉函数 \(\varphi(n)\)欧拉函数2 证明,当 \(p, q\) 为不相同的素数时,\(\varphi(n) = (p-1)(q-1)\)
  4. 随机选择一个整数 \(e\),满足两个条件:\(\varphi(n)\)\(e\) 互质,且 \(1 < e < \varphi(n)\)
  5. 计算 \(e\) 对于 \(\varphi(n)\) 的模反元素 \(d\),也就是说找到一个 \(d\) 满足 \(ed \equiv 1 \mod \varphi(n)\)。这个式子等价于 \(ed - 1 = k \times \varphi(n)\),实际上就是对于方程 \(ed - k \times \varphi(n) = 1\)\((d,k)\) 的整数解。这个方程可以用扩展欧几里得算法3求解。
  6. 最终把 \((e,n)\) 封装成公钥,\((d,n)\) 封装成私钥。

由于理论太枯燥,我们来举个实际例子运行一遍这个算法。

  1. 随机选择两个不相同的素数 \(p,q\)。我们选择 \(p=103, q=97\)
  2. \(p,q\) 相乘,\(n=103 \times 97 = 9991\)
  3. \(\varphi(n)=(103-1)(97-1)=9792\)
  4. 随机选择一个 \(e = 1213\),满足 \(\varphi(n)\)\(e\) 互质且 \(1 < e < \varphi(n)\)
  5. 计算 \(e\) 对于 \(\varphi(n)\) 的模反元素 \(d\),即代入方程 \(ed - k \times \varphi(n)=1\) 求整数解。将 \(e=1213,\varphi(n)=9792\) 代入方程,得到 \(1213 \times d - 9792 \times k = 1\),很容易可以找到 \((k,d)\) 的一组解 \(k=510, d=4117\)
  6. 封装公钥和私钥,最终得到的公钥 \((e,n)=(1213, 9991)\),私钥 \((d,n)=(4117, 9991)\)。 至此为止,我们有了原文 \(M\) ,公钥 \((e,n)\) 和私钥 \((d,n)\)。有了这些信息就可以开始加密和解密了。

2.2.1 加密

\(\textit{RSA}\) 算法中,加密过程实际上就是利用公钥 \((e,n)\) 计算 \(C = M^e (mod \ n)\)。假设原文 \(M=6\),代入上面的值,得到 \(C = 6^{1213} (mod \ 9991) = 7863\)。 于是 \(C=7863\),Alice就把 \(7863\) 发给了Bob。

2.2.2 解密

Bob收到了密文 \(C=7863\),就用自己的私钥 \((d,n)=(4117, 9991)\) 进行解密。\(\textit{RSA}\) 证明,原文的 \(e\) 次方对 \(n\) 取模恒等于 \(c\)\(d\) 次方,即 \(C^d ≡ M^e (mod \ n)\) 一定成立,所以 \(M = C^d mod \ n\)。代入 \(C,d,n\) 的值,得到 \(M = 7863^{4117} mod \ 9991 = 6\)

所以Bob就从密文 \(C\) 和私钥 \((d,n)=(4117, 9991)\) 知道了加密之前的原文 \(M=6\)

在整个通信过程Alice只用到了公钥 \((e,n)\) 进行加密,Bob只用到了私钥 \((d,n)\) 解密,没有任何关于秘钥的传递,只有加密后的密文 \(C\) 有可能在通信中被窃听到。

2.3 为什么RSA可以保证加密通信不被破解?

回顾上面的加密过程,我们用到了六个变量: \(p,q,n,\varphi(n),e,d\),其中只有公钥 \((e,n)\) 是公开的。想要破解密文,只要知道私钥 \((d,n)\),计算 \(M = C^d mod \ n\) 就可以破解 \(\textit{RSA}\) 算法。

那么,有没有可能在已知公钥 \((e,n)\) 的情况下,推导出私钥 \((d,n)\)

根据 \(\textit{RSA}\) 构造的规则(见上述 \(\textit{RSA}\) 加密过程1-6步),可以得到以下信息:

  1. 因为公钥中已知 \(n\),只要计算出 \(d\),就能得到私钥。

  2. \(ed ≡ 1 (mod \varphi(n))\),需要知道 \(e\)\(\varphi(n)\) 的值来求出 \(d\)。因为在公钥中已知 \(e\),所以只要求出 \(\varphi(n)\) 的值。

  3. \(\varphi(n)=(p-1)(q-1)\),要求出 \(\varphi(n)\) 的值,需要求出 \(p,q\) 的值。

  4. \(n=p \times q\),想要求出 \(p,q\) 的值,必须对 \(n\) 做因数分解。

结论:如果 \(n\) 可以被因数分解,\(d\) 就可以沿着4,3,2,1步骤推出,也就意味着私钥被破解。

但是大整数的质因数分解4,是一件非常困难的事情。目前,除了暴力破解,还没有发现别的有效方法。

阅读全文 »

By Long Luo

一、简单与复杂

一生二,二生三,三生万物。

三年前,当自己在学校图书馆看书时,突然心里深处涌出的一种冲动,让我重拾幼年时未能发育的音乐细胞时。当时以迅雷不及掩耳之势去借了几本乐理书,认真研读,虽然到现在还是一无所成…

但音乐那种组合之美,却让我回味至今。从古至今,世间音乐不过是几十个音符组合而已,都在一架钢琴的诠释范围之内。我想起了DNA里面的4对碱基对,地球上缤纷复杂的生命均以其为基础。

如同五彩缤纷的万花筒拆开之后,却只是一些小纸片和玻璃而已

可是我想通了此节之,却不能流畅地在吉他上弹奏一曲最简单的《欢乐颂》,也分辨不了不同的和弦,听不出歌曲的调式…

凡此种种, 都需要技术,尤其是复杂艰辛的训练,几年前就期望自己能够在舞台上一展才艺,可是到现在依然达不到登台的水平。

一边憎恶虚荣,一边找各种机会虚荣,在应该为了虚荣而努力的时候,拖延症又犯了。

知道复杂是由简单的东西所构成这很容易,但是如何能将简单组合成复杂以实现某种功能这才是道,也是我所追求的。

二、程序与代码

少壮不努力,老大搞IT

自从世界上第一台电脑在美国诞生之后,职业种类就增加了程序员这行,说的比较好听一点就是IT软件工程师。毕业之后,却因为阴差阳错走上了程序员这行,选择了无尽的加班和持续不断的学习,因为这行的知识基本上每2~3年就会迎来一个大的变化。

信息世界的比特流构成了这世界。

何谓程序?

何谓编程?

我写出一行行代码来换取柴米油盐,其实与我爸爸在工地上砌墙类似,区别不过在于我在电脑前摆弄的是键盘的砖块,他是在烈日下的建筑工地上而已。

不过,生于忧患,死于安乐。

三、时光

未觉池塘春草梦,阶前梧叶已秋声

偶然间看到这样一个比喻,“日子,就像一卷手纸。你瞧,刚买来时,老大一叠。用起来也不觉得担心,用得还挺慢。而当你看见那卷纸只有几层时,你会很珍惜地撕去每一张,用得那么快,仿佛一不留神,也就完了……”

是啊,日子如手纸,时光如手纸。日子,时光,生活,是三位一体的。

眼下,又到了年尾了,距离2014已只有几个月的时间了,似乎在不经意间,又长大了一岁。

是的,一年只有365个日子,365个日子经不起我们随意地挥霍,可是为什么总是只在年尾,才惊叹于一年365 天就如同365张手纸一样,一不留神,就用光了。于是,每个夜晚我们设想着明天,每次回首设想着此刻和将来。当黎明来临,初阳将我们包裹时,我们忽然又失去了记忆,没有了来时的脚步和许诺的信物。因为今天,意味着的是明天的昨天,将来的回首……

回顾这即将过去的一年,总会盘点些什么,可当我们试图想抓住一些什么、试图想把握一些什么的时候,日子却了无痕迹地在我们的身边,在我们的脸上,在我们的手上流逝。

我们的一生中总会有许许多多毫无特点却又独一无二的日子会跳入时间的洪流,无声无息地逝去?然后在我们突然想起的日子里成为新生活的一种怀念或祭奠?以此来表明自己曾经拥有?人的一生永远只会记住那些特别的一两天,在这独特的一天中发生了什么,成就了你,改变了你,成为人生中一段难以忘怀的回味。

当时并不知晓任何关于意义的东西,等待便等待,感叹便感叹,耽搁便耽搁,往往时间过去,留下来一滩思绪,如潮汐过后留下的贝壳,在一深一浅的沙滩上,刻着许多关于自由的记忆,这些记忆根植于湛蓝的海洋,记忆之事总是取之不尽,道之不竭,纯洁美好,却永远可望而不可及了。

回忆是精神的博物馆,明知自己回不去,争不到却还在自顾自地做出许多假设,猜测着许多种可能。一旦给予适当的机会,我们反倒犹豫,这一切都不可能重来。

阅读全文 »

By Long Luo

设备硬件信息

命令名称说明
cat /proc/cpuinfo显示 CPU info 的信息
cat /proc/meminfo校验内存使用
lspci -tv罗列 PCI 设备
lsusb -tv显示 USB 设备

磁盘信息

df -h 显示已经挂载的分区列表

ls -lSr | more 以尺寸大小排列文件和目录

du -sh dir1 估算目录 ‘dir1’ 已经使用的磁盘空间

du -sk * | sort -rn 以容量大小为依据依次显示文件和目录的大小

rpm -q -a –qf ‘%10{SIZE}t%{NAME}n’ | sort -k1,1n 以大小为依据依次显示已安装的 rpm 包所使用的空间(fedora,RedHat 类系统)

dpkg-query -W -f=‘\({Installed-Size10}t\){Package}n’ | sort -k1,1n 以大小为依据显示已安装的 deb 包所使用的空间(ubuntu,debian 类系统)

dmidecode -q 显示硬件系统部件 -(SMBIOS/DMI)

hdparm -i /dev/hda 罗列一个磁盘的架构特性

hdparm -tT /dev/sda 在磁盘上执行测试性读取操作

cat /proc/interrupts 显示中断

cat /proc/swaps 显示哪些 swap 被使用

cat /proc/version 显示内核的版本

cat /proc/net/dev 显示网络适配器及统计

cat /proc/mounts 显示已加载的文件系统

date 显示系统日期

cal 2007 显示 2007 年的日历表

date 041217002007.00 设置日期和时间 - 月日时分年.秒

clock -w 将时间修改保存到 BIOS

阅读全文 »

By Long Luo

一、引言

在上一篇 深入剖析printf函数(上):如何不借助第三方库在屏幕上输出”Hello World”? 里,我们已经实现了用汇编语言在屏幕上输出了“Hello World”, 迈出了万里长征的第一步,但是我们知道实际的printf的功能是十分强大的,它和scanf一样属于标准输入输出的一种格式化函数,我们一般是这样使用它的:

1
printf()的基本形式:printf("格式控制字符串",变量列表);

二、格式化输出

printf()函数是格式输出函数,请求printf()打印变量的指令取决与变量的类型.

例如,在打印整数是使用%d符号,在打印字符是用%c符号.这些符号被称为转换说明.因为它们指定了如何不数据转换成可显示的形式

下列列出的是ANSI C标准printf()提供的各种转换说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
转换说明及作为结果的打印输出
%a 浮点数、十六进制数字和p-记数法(C99)
%A    浮点数、十六进制数字和p-记法(C99)
%c    一个字符 
%d    有符号十进制整数 
%e    浮点数、e-记数法
%E    浮点数、E-记数法
%f    浮点数、十进制记数法  
%g    根据数值不同自动选择%f或%e.
%G    根据数值不同自动选择%f或%e.
%i 有符号十进制数(与%d相同)
%o    无符号八进制整数
%p    指针    
%s    字符串
%u    无符号十进制整数
%x    使用十六进制数字0f的无符号十六进制整数 
%X    使用十六进制数字0f的无符号十六进制整数
%%    打印一个百分号

三、形参列表的读入

printf函数的参数列表是如下的形式:

1
int printf(const char *fmt, ...)

类似于上面参数列表中的token:…,这个是可变形参的一种写法。当传递参数的个数不确定时,就可以用这种方式来表示。

但是电脑比程序员更笨,函数体必须知道具体调用时参数的个数才能保证顺利执行,那么我们必须寻找一种方法来了解参数的个数。

让我们先回到代码中来:

阅读全文 »

By Long Luo

前言

—“你为什么要去登珠穆朗玛?”

当美国《纽约时报》记者问英国登山家乔治·马洛里。

—“Because it is there(因为山在那里)。”

一、 内核的诱惑

会当凌绝顶,一览众山小。

内核,是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性

几十年来,内核以它那深深的魅力吸引着无数的码农为之倾倒,一代又一代的码农们从青青葱葱走向硕果累累,从风华正茂走向耄耋之年,也走出了现在多姿多彩的世界。

内核就像一位风姿卓约的美女,多少码农欲一亲芳泽而不得。Linux内核是庞大复杂的,超过 600 万行的代码,就如同珠穆朗玛峰一样那样让人望而生畏。初学者一踏入,绝大多数会不自觉地迷失在这座庞大的迷宫里。

二、用printf撕开一个小小的口子…

作为一名内核小白,我也期望着那天能登上Linux内核这座高峰,一览其风采,但高原反应可不是闹着玩的。 既然等不了珠穆朗玛峰,那就先试试攀登莲花山吧…

每一位初学者都学习过下面这个例子,

—没看过? —拖出去,XX了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/************************************************************************************
** File: - Z:\code\c\LLprintf\print0.1\LLapp.c
**
** Copyright (C), Long.Luo, All Rights Reserved!
**
** Description:
** LLapp.c
**
** Version: 0.1
** Date created: 21:30:00,10/01/2013
** Author: Long.Luo
**
** --------------------------- Revision History: --------------------------------
** <author> <data> <desc>
**
************************************************************************************/

#include <stdio.h>

int main(void)
{
printf("Hello, World!\n");

return 0;
}

我们通过调用 printf 就可以实现在屏幕上输出一段字符? —为什么呢? —假如我们不用 printf ,怎么做呢?

printf里面蕴含着什么样的秘密呢?

阅读全文 »
0%