开篇第一句话,就是“小白继续,有实际经验的兄弟们可以洗洗睡了”,因为这个 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#】聊聊不需要记密码的密码管理补充帖 —— 具体实现的更多相关文章

  1. Ubuntu16---安装mysql5.7未提示输入密码,安装后修改mysql密码默认密码

    Ubuntu16安装mysql5.7未提示输入密码,安装后修改mysql密码默认密码 mysql默认密码为空 但是使用mysql -uroot -p 命令连接mysql时,报错 ERROR 1045 ...

  2. Postgres使用ALTER USER命令修改用户的密码、密码过期,锁定,解锁

    使用ALTER USER命令修改用户的密码.密码过期,锁定,解锁 (1)修改用户的口令,将用户的口令修改为新的密码 highgo=#create user test with password ‘te ...

  3. linux和windows互传文件/用户配置文件和密码配置文件/用户组管理/用户管理

    2.27linux和windows互传文件 3.1 用户配置文件和密码配置文件 3.2 用户组管理 3.3 用户管理 linux和windows互传文件 显示日期date [root@centos_1 ...

  4. Ubuntu 破解密码及用户管理

    Ubuntu 破解密码及用户管理 ubuntu 16.04 破解密码 useradd 实现以下要求 1.ubuntu16.04破解密码 2.创建下面的用户.组和组成员关系 名字为xipudata 的组 ...

  5. Laravel实现找回密码及密码重置的例子

    https://mp.weixin.qq.com/s/PO5f5OJPt5FzUZr-7Xz8-g Laravel实现找回密码及密码重置功能在php实现与在这里实现会有什么区别呢,下面我们来看看Lar ...

  6. MYSQL命令练习及跳过数据库密码进行密码重新设置

        2.看当前所有数据库:show databases; 3.进入mysql数据库:use mysql; 4.查看mysql数据库中所有的表:show tables; 5.查看user表中的数据: ...

  7. 【C#】聊聊不需要记密码的密码管理

    密码管理(Password Management)肯定所有人都不会陌生,密码管理的来源也是来自于实际需求,当人们需要使用到密码的场景越来越多,场景也越来越复杂,密码的记录就成为了“难题”和“负担”,很 ...

  8. git ssh https 踩坑记 ---- 域账号密码更新

    前几天突然通知要更新公司的域账号密码,然后git pull就一直报 fatal: Authentication failed for 'https://git ... 很奇怪的是,有一个项目git p ...

  9. MySQL--忘记MYSQL管理员密码

    如root用户密码,可以按照以下方式来修改: STEP1: 停止MySQL服务 ps -ef | grep -v 'grep' | grep 'mysqld' | awk '{print $2}' | ...

随机推荐

  1. C#-简单的定时器(C# ConsoleApp) ---ShinePans

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hpbmVwYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...

  2. WeakReference and WeakHashMap

    弱引用通过WeakReference类实现,弱引用和软引用很像,但弱引用的引用级别更低.对于只有弱引用的对象而言,当系统垃圾回收机制运行时,不管系统北村是否足够,总会回收该对象所占用的内存.当然,并不 ...

  3. 脉冲神经网络Spiking neural network

    (原文地址:维基百科) 简单介绍: 脉冲神经网络Spiking neuralnetworks (SNNs)是第三代神经网络模型,其模拟神经元更加接近实际,除此之外,把时间信息的影响也考虑当中.思路是这 ...

  4. angular.js的路由和模板在asp.net mvc 中的使用

    angular.js的路由和模板在asp.net mvc 中的使用 我们知道angular.js是基于mvc 的一款优秀js框架,它也有一套自己的路由机制,和asp.net mvc 路由不太一样.as ...

  5. Android注入事件的三种方法比较

    方法1:使用内部APIs 该方法和其他所有内部没有向外正式公布的APIs一样存在它自己的风险.原理是通过获得WindowManager的一个实例来访问injectKeyEvent/injectPoin ...

  6. 【 c语言中无符号和有符号的加法运算】【深入理解】--【sky原创】

    原文:[ c语言中无符号和有符号的加法运算][深入理解]--[sky原创]   第一题 #include<stdio.h> int main() { unsigned int a=6; i ...

  7. Installshield关于.NET安装时需要重启动的处理办法,以及延伸出的重启后继续安装的安装包的一点想法

    原文:Installshield关于.NET安装时需要重启动的处理办法,以及延伸出的重启后继续安装的安装包的一点想法 很多朋友做安装包的时候,所打包的软件需要.NET Framework之类的环境,他 ...

  8. LibVLC video controls

    原文 http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__video.html VLC  3.0.0-git ...

  9. openwrt_git_pull命令提示merger冲突时如何解决?

    直接贴代码 tf@ubuntu:~/projects/openwrt1407$ git pull Updating 331ecb0..d12dc6e error: Your local changes ...

  10. .net的页面在大并发下出现503错误

    .net的页面在大并发下偶尔出现503错误 我们开发了一个回调页面,由一个工具负责调用,由于压力非常大,回调页面通过6台服务器负载均衡的: 最近业务系统又再次扩容,回调页面压力成倍增加,在高峰时间段偶 ...