## 摘要
本文介绍一款开源密码管理工具[**onepw**](https://github.com/mkideal/onepw)。
在密码管理器中`1Password`,`KeePass`都是大名顶顶,都有UI界面,而这里要讲的`onepw`则是一款命令行下的密码管理器。`onepw`仅仅只有几个命令: `init`,`add`,`rm`,`ls`,`find`。`onepw` 使用AES-256加密算法和CFB加密模式对密码和帐号进行加密,为每个帐号和密码随机一个初始化向量(IV)。
![screenshot.png](http://www.mkideal.com/images/onepw-screenshot.png)
## 工作原理
1) 生成AES加密算法所需的Key(Key是不能记录下来的),它由牢记于你心中的主密码得到。
+--------+ +-----+
| Master | MD5Sum | |
| Pass |========>| Key |
| Word | | |
+--------+ +-----+
2) 对帐号和密码分别按下面的流程进行加密
+-----------+
| |
| Random IV |==|
| | | +------------+
+-----------+ | CFB Encrypter | |
|===============>| CipherText |
+-----------+ | AES Cipher | |
| | | with Key +------------+
| PlainText |==|
| |
+-----------+
加密部分的代码如下:
```golang
func (box *Box) encrypt(pw *Password) error {
block, err := aes.NewCipher([]byte(md5sum(box.masterPassword)))
if err != nil {
return err
}
if len(pw.AccountIV) != block.BlockSize() {
pw.AccountIV = make([]byte, block.BlockSize())
// crand aliases crypto/rand
if _, err := crand.Read(pw.AccountIV); err != nil {
return err
}
}
if len(pw.PasswordIV) != block.BlockSize() {
pw.PasswordIV = make([]byte, block.BlockSize())
if _, err := crand.Read(pw.PasswordIV); err != nil {
return err
}
}
pw.CipherAccount = cfbEncrypt(block, pw.AccountIV, []byte(pw.PlainAccount))
pw.CipherPassword = cfbEncrypt(block, pw.PasswordIV, []byte(pw.PlainPassword))
return nil
}
func cfbEncrypt(block cipher.Block, iv, src []byte) []byte {
cfb := cipher.NewCFBEncrypter(block, iv)
dst := make([]byte, len(src))
cfb.XORKeyStream(dst, src)
return dst
}
```
好了,`onepw`的核心其实就这点了,此外就是命令包装,用来对密码盒进行管理。一般来说,`onepw`的使用工作流如下:
### 设置环境变量
```sh
export ONEPW_FILE="/home/user/mypasswords/password.data"
export ONEPW_MASTER="XXXYYYZZZ"
```
### init
使用 init 命令进行初始化,这将创建一个密码本文件 $ONEPW_FILE。需要说明的是,任何对密码的查看和操作都需要提供主密码,为避免频繁输入,可设置 `ONEPW_MASTER` 环境变量,`onepw`会尝试读取这个环境变量
```sh
onepw init
```
### add
使用 add 命令添加新密码或更新原密码
![add命令的帮助](http://www.mkideal.com/images/onepw-add-help.png)
* 如果 `add` 命令没有指定 `--id` 参数,则为添加新密码
* 否则更新指定 ID 的密码,若 ID 不存在则报错
* 可以指定 `--tag`,`--site` 等参数对密码存储一些额外信息
* 虽然可以通过 `--pw` 和 `--cpw` 参数指定密码和确认密码,但是建议不指定这些参数,而是由提示 type the password 或 repeat the password 后输入完成
```shell
onepw add -c email -u user@example.com
```
上面这条命令执行后会在终端输出 type the password 的提示,此时输入密码,然后会输出 repeat the password 的提示,再重复刚才的密码即可。目前仅要求密码长度至少6个字符,将来将加入一些别的强制性安全要求。
### list
使用 list 命令查看当前已有的所有密码(ls 是 list 命令的别名)
```shell
onepw ls
```
命令的输出像这样
```shell
+---------+----------+------------------+----------+---------------------------+
| ID | CATEGORY | ACCOUNT | PASSWORD | UPDATED_AT |
+---------+----------+------------------+----------+---------------------------+
| d9437f0 | email | user@example.com | 123456 | 2016-04-29T07:54:36+08:00 |
+---------+----------+------------------+----------+---------------------------+
```
### remove
使用 remove 命令根据ID前缀删除密码(rm,del,delete 是 remove 命令的别名)
```shell
onepw remove d9
```
* remove 指令可以一次删除多个密码,只需要输入多个ID参数即可,像这样: `onepw rm ID1 ID2 ...`
* 如果指定的某个ID前缀有歧义(即存在2个及以上的密码的ID包含此前缀),那么删除将失败,除非指定 `-a` 或 `--all` 标记
* 如果没有指定任何ID,而提供了 `-a` 或 `--all` 参数则将清空所有密码
### find
使用 find 命令查找密码
```shell
onepw find email
```
find 命令需要一个参数作为匹配文本(暂不支持正则表达式),然后从每个密码的 ID,Category,Account,Password,Tags,Site中检测是否包含此文本,如果是,此密码将列入到结果中显示
### generate
使用`generate`命令生成密码, `gen`是`generate`的别名.
```sh
onepw gen 16
```
输入`onepw gen -h`获取帮助.
### info
使用 `info`命令查看密码的详细信息
## 额外的话
`onepw`完全可以在本地进行密码的管理,也可以自行同步到云端,无论如何,都建议做版本管理。比如自己在本地建立一个git仓库,每次操作密码后做一次提交,这样中途如果出现误操作也可通过版本系统进行恢复。同时可以在bitbucket上创建一个私人仓库,将密码托管其上,从此只需记住主密码,到哪儿都可以进行密码管理了。
**主密码千万要记住且保密了**
`onepw`虽然从功能上讲基本够用,但是如果有各种平台的UI,使用起来会方便许多。后面将会对`onepw`进行一些优化和安全强化,完了,开发UI界面进行可视化管理。
`onepw` 开源在github上 [**https://github.com/mkideal/onepw**](https://github.com/mkideal/onepw),命令行接口使用[**https://github.com/mkideal/cli**](https://github.com/mkideal/cli) 构建。
有疑问加站长微信联系(非本文作者)