【C#】聊聊不需要记密码的密码管理补充帖 —— 具体实现
开篇第一句话,就是“小白继续,有实际经验的兄弟们可以洗洗睡了”,因为这个 Lite 版是个实验性的实现,也由于水平原因源码不忍直视,所以如果你坚持看完了,请留下宝贵意见。
以下,干货:
基本模式:
程序使用“钥匙”对用户需要加密的内容进行自动加密,加密完成后,导出数据和“钥匙”为文件,用户自行保管文件即可。解密时,告诉程序要用哪个钥匙,程序无需用户任何输入即可自动完成解密,解密失败也不会影响用户数据。
此模式好处:
用户无需关心数据如何保存,更不必管“钥匙”具体什么样(无需指定密码),只要在使用时告诉程序“来,用这个钥匙,给我解这个数据”,就像插入钥匙打开锁头一样,至于钥匙长什么样,管它呢!
不能被破解吗?
理论上哪有不能被破解的东西,但是这种方式也很安全,因为你需要满足下面几种方式才能被破解:
1. 暴力算法,纯技术流,黑客拿到你的数据文件,看到一串乱码,但由于黑客经验极其丰富一看就知道大概是什么算法算出来的,好,他就开始暴力破解....唉,我不好说用多长时间,但是平民小白被牛B黑客这么死心塌地破解的概率恐怕比中国男足进世界杯还小吧。
2. 黑客必须同时得到你的数据文件和“钥匙”文件 & 还得知道你的A钥匙就是开A数据的 & 还得知道怎么使用钥匙开你的数据文件(程序逻辑),这概率...也够小的吧。
数据逻辑:
1. 程序里,我设定了四个基础数据,来组成一个“隐私内容项”,分别是标题、关键字、加密内容和校验码;
#region Statements /// <summary>
/// 标题
/// </summary>
private string _title;
/// <summary>
/// 关键内容,比如登录账号
/// </summary>
private string _keyword;
/// <summary>
/// 加密后的密文
/// </summary>
private string _ciphertext;
/// <summary>
/// 校验值
/// </summary>
private string _checkcode; #endregion
隐私内容类
2. 隐私内容类是承载用户信息的基本单元,本身没有功能,所以设计一个管理它使用它的类,暂时叫做“内容管理类”吧。内容管理类的功能是接收界面反馈,添加、移除“隐私内容项”,使用“加密服务”来实现加密解密功能等等;
3. 内容管理类自己没有加解密功能,是要调用实现加解密功能的类,暂时成为“密钥服务”吧,密钥服务要实现密钥新生、密钥导入、密钥导出、加密、解密、创建Hash、验证等功能;
public class CryptogramService
{
public byte[] Encrypt(byte[] data){ }
public byte[] Decrypt(byte[] data){ }
public CryptogramService LoadKey(string path){ }
public byte[] GetKey(){ }
}
密钥服务
4. 内容管理类可以将所有“隐私内容项”导出成文件;
5. 密钥服务类可以将密钥信息保存成文件;
以上代码仅供参考,实际应该被实现成接口,和调用方实现松耦合,我在程序里暂时写死了 ^^,至此 iPassword Lite 主要功能所使用到的数据都描述了,总结起来就是“内容管理”接收用户输入,创建一个“隐私内容”,调用“密钥服务”加密“隐私内容”
密钥服务:
1. 创建新钥匙:程序启动时,默认创建新的“钥匙”,钥匙的齿什么样用户不用管,其实程序也不知道;
2. 导入钥匙:程序可以导入用户指定的“钥匙”,导入钥匙的作用是让用户使用自选的钥匙来开锁;
3. 导出钥匙:程序可以保存当前使用的钥匙为文件;
界面实现:
在 iPassword Lite 中使用了 ListBox 自绘的方式呈现,这恐怕也是整个程序中唯一可以给其他朋友借鉴一二的地方,倒不是多高明,是因为其它的内容实在没什么展示代码的意义。一步步说吧
1. 设置 ListBox,其 DrawMode 设置成 OwnerDrawVariable 就可以自绘了;
2. 绘制成什么样,我现在的做法是 头像 + 标题 + 描述文字(描述文字暂时是关键字内容)的现实方式,左侧头像,右侧由标题和描述文字上下左对齐排列;
3. 测量项目,在绘制前要设定好 ListBox 的每个 Item 的大小,宽度好办,我就设置 ListBox 的 ClientSize 就可以了,高度是个问题,我的方式是上空白 + 头像高度 + 下空白的方式,但是我的头像高度又由标题文字和描述文字及留白组成,所以实际计算方式是【上留白 + 标题 + 描述文字 + 下留白】来组成,下面是实际代码
private void profileListBox_MeasureItem(object sender, MeasureItemEventArgs e)
{
// 高度 = 上下通用间隔 + 标题和描述所有文本间隔
this.MeasureTitleHeight = TextRenderer.MeasureText("中", this.FontForTitle).Height;
this.MeasureDescriptionHeight = TextRenderer.MeasureText("中", this.FontForDescription).Height;
var allTextHeight = this.MeasureTitleHeight + this.MeasureDescriptionHeight + this.TextPadding * ; e.ItemHeight = this.ItemPadding * + allTextHeight;
e.ItemWidth = profileListBox.ClientRectangle.Width; // 设置头像尺寸
this.HeadshotSize = new Size(allTextHeight, allTextHeight);
}
测量 Item
4. 绘制。绘制比较麻烦,一开始我是所有元素分别绘制的,发现闪烁明显,后来采用绘制到内存图像,再把图像绘制到界面的方式,即双缓冲的思路。具体方式是这样:
1). 创建内容图像
// 准备图形
Bitmap itemImage = new Bitmap(e.Bounds.Width, e.Bounds.Height, e.Graphics);
var itemGraphics = Graphics.FromImage(itemImage);
itemGraphics.CompositingQuality = CompositingQuality.HighQuality;
itemGraphics.SmoothingMode = SmoothingMode.AntiAlias;
var itemRect = new Rectangle(, , e.Bounds.Width, e.Bounds.Height);
内存图像
2). 绘制背景
// 绘制背景
var bgBrush = new SolidBrush(Color.White);
itemGraphics.FillRectangle(bgBrush, itemRect);
bgBrush.Dispose();
绘制背景
3). 绘制头像,获取标题第一个字,将其绘制到头像圆形中
// 绘制头像圆形
var headImageBrush = new SolidBrush(Color.DarkTurquoise);
if (isSelected)
{
headImageBrush.Color = Color.Tomato;
}
var headImageRect = new Rectangle(new Point(itemRect.X + this.ItemPadding, itemRect.Y + this.ItemPadding), this.HeadshotSize);
itemGraphics.FillEllipse(headImageBrush, headImageRect);
headImageBrush.Dispose(); // 绘制头像中的字符
string hsLetter = title.Substring(, ); // 取标题第一个字符作为头像字显示
var letterBrush = new SolidBrush(Color.White);
var letterSF = new StringFormat(StringFormatFlags.NoWrap);
letterSF.Alignment = StringAlignment.Center;
letterSF.LineAlignment = StringAlignment.Center;
var letterRect = headImageRect;
itemGraphics.DrawString(hsLetter, this.FontForHeadshot, letterBrush, letterRect, letterSF); letterBrush.Dispose();
letterSF.Dispose();
绘制头像和文字
4). 绘制标题和描述文字绘制描述文字
//draw title
var titleString = title;
var titleBrush = new SolidBrush(Color.FromKnownColor(KnownColor.WindowText));
var titleRect = new Rectangle(itemRect.X + this.ItemPadding + this.HeadshotSize.Width + this.ItemPadding,
itemRect.Y + this.ItemPadding,
itemRect.Width - (itemRect.X + this.ItemPadding + this.HeadshotSize.Width + this.ItemPadding),
this.TextPadding + this.MeasureTitleHeight + this.TextPadding);
var titleSF = new StringFormat(StringFormatFlags.NoWrap);
titleSF.Alignment = StringAlignment.Near;
titleSF.LineAlignment = StringAlignment.Center; itemGraphics.DrawString(titleString, this.FontForTitle, titleBrush, titleRect, titleSF);
titleBrush.Dispose();
titleSF.Dispose(); //draw keyword string
var kwString = keyword;
var kwBrush = new SolidBrush(Color.FromKnownColor(KnownColor.GrayText));
var kwRect = new Rectangle(itemRect.X + this.ItemPadding + this.HeadshotSize.Width + this.ItemPadding,
itemRect.Y + this.ItemPadding + this.TextPadding * + this.MeasureTitleHeight,
itemRect.Width - (itemRect.X + this.ItemPadding + this.HeadshotSize.Width + this.ItemPadding),
this.TextPadding * + this.MeasureDescriptionHeight);
var kwSF = new StringFormat(StringFormatFlags.NoWrap);
kwSF.Alignment = StringAlignment.Near;
kwSF.LineAlignment = StringAlignment.Center; itemGraphics.DrawString(kwString, this.FontForDescription, kwBrush, kwRect, kwSF);
kwBrush.Dispose();
kwSF.Dispose();
绘制头像和文字
5). 把图像绘制到界面
var image = OwnDrawItemToImage(e);
if(image !=null)
{
e.Graphics.DrawImageUnscaled(image, e.Bounds);
image.Dispose();
}
将图像绘制到界面
至此,界面绘制完成,这种方式可以避免一个 Item 被直接在界面绘制多次,造成效率低下和闪烁。
【C#】聊聊不需要记密码的密码管理补充帖 —— 具体实现的更多相关文章
- Ubuntu16---安装mysql5.7未提示输入密码,安装后修改mysql密码默认密码
Ubuntu16安装mysql5.7未提示输入密码,安装后修改mysql密码默认密码 mysql默认密码为空 但是使用mysql -uroot -p 命令连接mysql时,报错 ERROR 1045 ...
- Postgres使用ALTER USER命令修改用户的密码、密码过期,锁定,解锁
使用ALTER USER命令修改用户的密码.密码过期,锁定,解锁 (1)修改用户的口令,将用户的口令修改为新的密码 highgo=#create user test with password ‘te ...
- linux和windows互传文件/用户配置文件和密码配置文件/用户组管理/用户管理
2.27linux和windows互传文件 3.1 用户配置文件和密码配置文件 3.2 用户组管理 3.3 用户管理 linux和windows互传文件 显示日期date [root@centos_1 ...
- Ubuntu 破解密码及用户管理
Ubuntu 破解密码及用户管理 ubuntu 16.04 破解密码 useradd 实现以下要求 1.ubuntu16.04破解密码 2.创建下面的用户.组和组成员关系 名字为xipudata 的组 ...
- Laravel实现找回密码及密码重置的例子
https://mp.weixin.qq.com/s/PO5f5OJPt5FzUZr-7Xz8-g Laravel实现找回密码及密码重置功能在php实现与在这里实现会有什么区别呢,下面我们来看看Lar ...
- MYSQL命令练习及跳过数据库密码进行密码重新设置
2.看当前所有数据库:show databases; 3.进入mysql数据库:use mysql; 4.查看mysql数据库中所有的表:show tables; 5.查看user表中的数据: ...
- 【C#】聊聊不需要记密码的密码管理
密码管理(Password Management)肯定所有人都不会陌生,密码管理的来源也是来自于实际需求,当人们需要使用到密码的场景越来越多,场景也越来越复杂,密码的记录就成为了“难题”和“负担”,很 ...
- git ssh https 踩坑记 ---- 域账号密码更新
前几天突然通知要更新公司的域账号密码,然后git pull就一直报 fatal: Authentication failed for 'https://git ... 很奇怪的是,有一个项目git p ...
- MySQL--忘记MYSQL管理员密码
如root用户密码,可以按照以下方式来修改: STEP1: 停止MySQL服务 ps -ef | grep -v 'grep' | grep 'mysqld' | awk '{print $2}' | ...
随机推荐
- 远程数据client交换器
不太繁忙的文本. 要被写入
- XCL-Charts绘画面积图(AreaChart) 案件1
样本区域地图,发现区域图的时候把做向上注视位置图更具优势的管理. 在改变. 区域图网格和轴是不一样的处理与其它图, 它是用来表示其影响范围的覆盖范围,车桥无段伸出.在这里下处理. 代码: /** * ...
- .NET中IDisposable接口的基本使用
首先来看MSDN中关于这个接口的说明: [ComVisible(true)] public interface IDisposable { // Methods void Dispose(); } 1 ...
- GitBook配置
GitBook 是一个通过 Git 和 Markdown 来撰写书籍的工具.生成格式有:JSON.ePub.PDF.Website ! ================================ ...
- 项目管理实践 -- 健身小管家(Fitness housekeeper)的管理(4)
提前几天把检查更新的功能完成了.
- UVA The Sultan's Successors
题目例如以下: The Sultan's Successors The Sultan of Nubia has no children, so she has decided that thecou ...
- CentOS-6.3安装配置SVN
安装说明 系统环境:CentOS-6.3 安装方式:yum install (源码安装容易产生版本兼容的问题) 安装软件:系统自动下载SVN软件 检查已安装版本 #检查是否安装了低版本的SVN [ro ...
- C语言学习-数据结构 - 倒插法顺序表
// test20161106.cpp : Defines the entry point for the console application. // #include "stdafx. ...
- Android4.3引入的UiAutomation新框架官方简介
译者序:Google在Android 4.3发布时提供了一套新的UiAutomation框架来支持用户界面自动化测试,该框架通过运用已有的Accessibility APIs来模拟用户跟设备用户界面的 ...
- jq toggle1.9版本后不支持解决方案
<script type="text/javascript"> $(document).ready(function(){ $("button"). ...