沫欢 發表於 2019-6-19 22:58:00

Google Authenticator(谷歌身份验证器)C#版

<div>摘要:Google Authenticator(谷歌身份验证器),是谷歌公司推出的一款动态令牌工具,解决账户使用时遭到的一些不安全的操作进行的“二次验证”,认证器基于RFC文档中的HOTP/TOTP算法实现 ,是一种从共享秘钥和时间或次数一次性令牌的算法。在工作中可以通过认证器方式对账户有更好的保护,但是在查阅一些资料发现适合我这样的小白文章真的很少,针对于C#的文章就更加少了,本文主要是对C#如何使用Google Authenticator(谷歌身份验证器)进行探讨,有不足之处还请见谅。</div>
<h2>Google Authenticator(谷歌身份验证器)</h2>
<h3>什么是认证器?怎么对接?</h3>
<div>
<p>Google Authenticator(谷歌身份验证器)是微软推出的一个动态密令工具,它有两种密令模式。分别是“TOTP 基于时间”、“HOTP 基于计数器”,通过手机上 简单的设置就可以设定自己独一的动态密令, 那么我们怎么将我们的程序和认证器进行对接呢?其实谷歌认证器并不是需要我们对接这个工具的API而是通过算法来决定,谷歌使用使用HMAC算法生成密令,通过基于次数或者基于时间两个模板进行计算,因此在程序中只需要使用相同的算法即可与之匹配。</p>
</div>
<div>
<h4>TOTP 基于时间</h4>
<ul>
<li>HMAC算法使用固定为HmacSHA1</li>
<li>更新时长固定为30秒</li>
<li>APP端输入数据维度只有两个:账户名称(自己随意填写方便自己查看)和base32格式的key</li>
</ul>
</div>
<div>
<h4>HOTP 基于计数器</h4>
<p>基于计数器模式是根据一个共享秘钥K和一个C计数器进行算法计算</p>
</div>
<h3>认证器安装</h3>
<div>
<p>手机需要安装认证器:</p>
<ul>
<li>Android版:安卓版下载</li>
<li>IOS版:苹果版下载</li>
</ul>
</div>
<h3>效果图</h3>
<h3><img src="https://img2018.cnblogs.com/blog/1407129/201906/1407129-20190619224446456-757566347.gif" alt="" width="335" height="175"><img src="https://img2018.cnblogs.com/blog/1407129/201906/1407129-20190619224616709-1845395391.gif" alt="">容</h3>
<h3><span style="font-size: 1.5em">案例</span></h3>
<h3>控制台</h3>
<div>
<div class="cnblogs_code"><img id="code_img_closed_055caeba-c22e-44bf-bf70-51c2bd4c2a79" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_055caeba-c22e-44bf-bf70-51c2bd4c2a79" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_055caeba-c22e-44bf-bf70-51c2bd4c2a79" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System;
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Collections.Generic;
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Linq;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> GoogleAuthenticator
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>   <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Program
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">10</span>         <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Main(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] args)
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">12</span>             <span style="color: rgba(0, 0, 255, 1)">long</span> duration = <span style="color: rgba(128, 0, 128, 1)">30</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span>             <span style="color: rgba(0, 0, 255, 1)">string</span> key = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">xeon997@foxmail.com</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">14</span>             GoogleAuthenticator authenticator = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GoogleAuthenticator(duration, key);
</span><span style="color: rgba(0, 128, 128, 1)">15</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> mobileKey =<span style="color: rgba(0, 0, 0, 1)"> authenticator.GetMobilePhoneKey();
</span><span style="color: rgba(0, 128, 128, 1)">16</span>
<span style="color: rgba(0, 128, 128, 1)">17</span>             <span style="color: rgba(0, 0, 255, 1)">while</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span>               Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">手机端秘钥为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> mobileKey);
</span><span style="color: rgba(0, 128, 128, 1)">21</span>
<span style="color: rgba(0, 128, 128, 1)">22</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> code =<span style="color: rgba(0, 0, 0, 1)"> authenticator.GenerateCode();
</span><span style="color: rgba(0, 128, 128, 1)">23</span>               Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">动态验证码为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> code);
</span><span style="color: rgba(0, 128, 128, 1)">24</span>
<span style="color: rgba(0, 128, 128, 1)">25</span>               Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">刷新倒计时:</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> authenticator.EXPIRE_SECONDS);
</span><span style="color: rgba(0, 128, 128, 1)">26</span>
<span style="color: rgba(0, 128, 128, 1)">27</span>               System.Threading.Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">1000</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(0, 0, 0, 1)">                Console.Clear();
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">30</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">31</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">32</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>&nbsp;</p>
</div>
<h3>认证器类</h3>
<div>
<div class="cnblogs_code"><img id="code_img_closed_53732977-0088-4141-97be-dd6488d5880b" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_53732977-0088-4141-97be-dd6488d5880b" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_53732977-0088-4141-97be-dd6488d5880b" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> GoogleAuthorization;
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System;
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Security.Cryptography;
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text;
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> GoogleAuthenticator
</span><span style="color: rgba(0, 128, 128, 1)">6</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)">7</span>   <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> GoogleAuthenticator
</span><span style="color: rgba(0, 128, 128, 1)">8</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">9</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 10</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 初始化验证码生成规则
</span><span style="color: rgba(0, 128, 128, 1)"> 11</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 12</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="key"&gt;</span><span style="color: rgba(0, 128, 0, 1)">秘钥(手机使用Base32码)</span><span style="color: rgba(128, 128, 128, 1)">&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 13</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="duration"&gt;</span><span style="color: rgba(0, 128, 0, 1)">验证码间隔多久刷新一次(默认30秒和google同步)</span><span style="color: rgba(128, 128, 128, 1)">&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 14</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> GoogleAuthenticator(<span style="color: rgba(0, 0, 255, 1)">long</span> duration = <span style="color: rgba(128, 0, 128, 1)">30</span>, <span style="color: rgba(0, 0, 255, 1)">string</span> key = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">xeon997@foxmail.com</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 15</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 16</span>             <span style="color: rgba(0, 0, 255, 1)">this</span>.SERECT_KEY =<span style="color: rgba(0, 0, 0, 1)"> key;
</span><span style="color: rgba(0, 128, 128, 1)"> 17</span>             <span style="color: rgba(0, 0, 255, 1)">this</span>.SERECT_KEY_MOBILE =<span style="color: rgba(0, 0, 0, 1)"> Base32.ToString(Encoding.UTF8.GetBytes(key));
</span><span style="color: rgba(0, 128, 128, 1)"> 18</span>             <span style="color: rgba(0, 0, 255, 1)">this</span>.DURATION_TIME =<span style="color: rgba(0, 0, 0, 1)"> duration;
</span><span style="color: rgba(0, 128, 128, 1)"> 19</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 20</span>
<span style="color: rgba(0, 128, 128, 1)"> 21</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 22</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 间隔时间
</span><span style="color: rgba(0, 128, 128, 1)"> 23</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 24</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">long</span> DURATION_TIME { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)"> 25</span>
<span style="color: rgba(0, 128, 128, 1)"> 26</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 27</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 迭代次数
</span><span style="color: rgba(0, 128, 128, 1)"> 28</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 29</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> COUNTER
</span><span style="color: rgba(0, 128, 128, 1)"> 30</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 31</span>             <span style="color: rgba(0, 0, 255, 1)">get</span>
<span style="color: rgba(0, 128, 128, 1)"> 32</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 33</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> (<span style="color: rgba(0, 0, 255, 1)">long</span>)(DateTime.UtcNow - <span style="color: rgba(0, 0, 255, 1)">new</span> DateTime(<span style="color: rgba(128, 0, 128, 1)">1970</span>, <span style="color: rgba(128, 0, 128, 1)">1</span>, <span style="color: rgba(128, 0, 128, 1)">1</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, DateTimeKind.Utc)).TotalSeconds /<span style="color: rgba(0, 0, 0, 1)"> DURATION_TIME;
</span><span style="color: rgba(0, 128, 128, 1)"> 34</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 35</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 36</span>
<span style="color: rgba(0, 128, 128, 1)"> 37</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 38</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 秘钥
</span><span style="color: rgba(0, 128, 128, 1)"> 39</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 40</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">string</span> SERECT_KEY { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)"> 41</span>
<span style="color: rgba(0, 128, 128, 1)"> 42</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 43</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 手机端输入的秘钥
</span><span style="color: rgba(0, 128, 128, 1)"> 44</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 45</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">string</span> SERECT_KEY_MOBILE { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)"> 46</span>
<span style="color: rgba(0, 128, 128, 1)"> 47</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 48</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 到期秒数
</span><span style="color: rgba(0, 128, 128, 1)"> 49</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 50</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> EXPIRE_SECONDS
</span><span style="color: rgba(0, 128, 128, 1)"> 51</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 52</span>             <span style="color: rgba(0, 0, 255, 1)">get</span>
<span style="color: rgba(0, 128, 128, 1)"> 53</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 54</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> (DURATION_TIME - (<span style="color: rgba(0, 0, 255, 1)">long</span>)(DateTime.UtcNow - <span style="color: rgba(0, 0, 255, 1)">new</span> DateTime(<span style="color: rgba(128, 0, 128, 1)">1970</span>, <span style="color: rgba(128, 0, 128, 1)">1</span>, <span style="color: rgba(128, 0, 128, 1)">1</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, DateTimeKind.Utc)).TotalSeconds %<span style="color: rgba(0, 0, 0, 1)"> DURATION_TIME);
</span><span style="color: rgba(0, 128, 128, 1)"> 55</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 56</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 57</span>
<span style="color: rgba(0, 128, 128, 1)"> 58</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 59</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 获取手机端秘钥
</span><span style="color: rgba(0, 128, 128, 1)"> 60</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 61</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 62</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> GetMobilePhoneKey()
</span><span style="color: rgba(0, 128, 128, 1)"> 63</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 64</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (SERECT_KEY_MOBILE == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 65</span>               <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> ArgumentNullException(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SERECT_KEY_MOBILE</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 66</span>             <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> SERECT_KEY_MOBILE;
</span><span style="color: rgba(0, 128, 128, 1)"> 67</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 68</span>
<span style="color: rgba(0, 128, 128, 1)"> 69</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 70</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 生成认证码
</span><span style="color: rgba(0, 128, 128, 1)"> 71</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 72</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;</span><span style="color: rgba(0, 128, 0, 1)">返回验证码</span><span style="color: rgba(128, 128, 128, 1)">&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 73</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> GenerateCode()
</span><span style="color: rgba(0, 128, 128, 1)"> 74</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 75</span>             <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> GenerateHashedCode(SERECT_KEY, COUNTER);
</span><span style="color: rgba(0, 128, 128, 1)"> 76</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 77</span>
<span style="color: rgba(0, 128, 128, 1)"> 78</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 79</span>         <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 按照次数生成哈希编码
</span><span style="color: rgba(0, 128, 128, 1)"> 80</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 81</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="secret"&gt;</span><span style="color: rgba(0, 128, 0, 1)">秘钥</span><span style="color: rgba(128, 128, 128, 1)">&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 82</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="iterationNumber"&gt;</span><span style="color: rgba(0, 128, 0, 1)">迭代次数</span><span style="color: rgba(128, 128, 128, 1)">&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 83</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;param name="digits"&gt;</span><span style="color: rgba(0, 128, 0, 1)">生成位数</span><span style="color: rgba(128, 128, 128, 1)">&lt;/param&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 84</span>         <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;returns&gt;</span><span style="color: rgba(0, 128, 0, 1)">返回验证码</span><span style="color: rgba(128, 128, 128, 1)">&lt;/returns&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 85</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">string</span> GenerateHashedCode(<span style="color: rgba(0, 0, 255, 1)">string</span> secret, <span style="color: rgba(0, 0, 255, 1)">long</span> iterationNumber, <span style="color: rgba(0, 0, 255, 1)">int</span> digits = <span style="color: rgba(128, 0, 128, 1)">6</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 86</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 87</span>             <span style="color: rgba(0, 0, 255, 1)">byte</span>[] counter =<span style="color: rgba(0, 0, 0, 1)"> BitConverter.GetBytes(iterationNumber);
</span><span style="color: rgba(0, 128, 128, 1)"> 88</span>
<span style="color: rgba(0, 128, 128, 1)"> 89</span>             <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (BitConverter.IsLittleEndian)
</span><span style="color: rgba(0, 128, 128, 1)"> 90</span> <span style="color: rgba(0, 0, 0, 1)">                Array.Reverse(counter);
</span><span style="color: rgba(0, 128, 128, 1)"> 91</span>
<span style="color: rgba(0, 128, 128, 1)"> 92</span>             <span style="color: rgba(0, 0, 255, 1)">byte</span>[] key =<span style="color: rgba(0, 0, 0, 1)"> Encoding.ASCII.GetBytes(secret);
</span><span style="color: rgba(0, 128, 128, 1)"> 93</span>
<span style="color: rgba(0, 128, 128, 1)"> 94</span>             HMACSHA1 hmac = <span style="color: rgba(0, 0, 255, 1)">new</span> HMACSHA1(key, <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 95</span>
<span style="color: rgba(0, 128, 128, 1)"> 96</span>             <span style="color: rgba(0, 0, 255, 1)">byte</span>[] hash =<span style="color: rgba(0, 0, 0, 1)"> hmac.ComputeHash(counter);
</span><span style="color: rgba(0, 128, 128, 1)"> 97</span>
<span style="color: rgba(0, 128, 128, 1)"> 98</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> offset = hash &amp; <span style="color: rgba(128, 0, 128, 1)">0xf</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 99</span>
<span style="color: rgba(0, 128, 128, 1)">100</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> binary =
<span style="color: rgba(0, 128, 128, 1)">101</span>               ((hash &amp; <span style="color: rgba(128, 0, 128, 1)">0x7f</span>) &lt;&lt; <span style="color: rgba(128, 0, 128, 1)">24</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">102</span>               | ((hash &amp; <span style="color: rgba(128, 0, 128, 1)">0xff</span>) &lt;&lt; <span style="color: rgba(128, 0, 128, 1)">16</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">103</span>               | ((hash &amp; <span style="color: rgba(128, 0, 128, 1)">0xff</span>) &lt;&lt; <span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">104</span>               | (hash &amp; <span style="color: rgba(128, 0, 128, 1)">0xff</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">105</span>
<span style="color: rgba(0, 128, 128, 1)">106</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> password = binary % (<span style="color: rgba(0, 0, 255, 1)">int</span>)Math.Pow(<span style="color: rgba(128, 0, 128, 1)">10</span>, digits); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 6 digits</span>
<span style="color: rgba(0, 128, 128, 1)">107</span>
<span style="color: rgba(0, 128, 128, 1)">108</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> password.ToString(<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">string</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">0</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">, digits));
</span><span style="color: rgba(0, 128, 128, 1)">109</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">110</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">111</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>&nbsp;</p>
<p><span style="font-size: 1.17em">Base32转码类</span></p>
</div>
<div>
<div class="cnblogs_code"><img id="code_img_closed_333f57cc-4312-4d81-b388-a2b62a46b77a" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_333f57cc-4312-4d81-b388-a2b62a46b77a" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_333f57cc-4312-4d81-b388-a2b62a46b77a" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System;
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> GoogleAuthorization
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)">4</span>   <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Base32
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">6</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[] ToBytes(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> input)
</span><span style="color: rgba(0, 128, 128, 1)">7</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">8</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrEmpty(input))
</span><span style="color: rgba(0, 128, 128, 1)">9</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 10</span>               <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> ArgumentNullException(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">input</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 11</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 12</span>
<span style="color: rgba(0, 128, 128, 1)"> 13</span>             input = input.TrimEnd(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">=</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 14</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> byteCount = input.Length * <span style="color: rgba(128, 0, 128, 1)">5</span> / <span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 15</span>             <span style="color: rgba(0, 0, 255, 1)">byte</span>[] returnArray = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 16</span>
<span style="color: rgba(0, 128, 128, 1)"> 17</span>             <span style="color: rgba(0, 0, 255, 1)">byte</span> curByte = <span style="color: rgba(128, 0, 128, 1)">0</span>, bitsRemaining = <span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 18</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> mask = <span style="color: rgba(128, 0, 128, 1)">0</span>, arrayIndex = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 19</span>
<span style="color: rgba(0, 128, 128, 1)"> 20</span>             <span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">char</span> c <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> input)
</span><span style="color: rgba(0, 128, 128, 1)"> 21</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 22</span>               <span style="color: rgba(0, 0, 255, 1)">int</span> cValue =<span style="color: rgba(0, 0, 0, 1)"> CharToValue(c);
</span><span style="color: rgba(0, 128, 128, 1)"> 23</span>
<span style="color: rgba(0, 128, 128, 1)"> 24</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (bitsRemaining &gt; <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 25</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 26</span>                     mask = cValue &lt;&lt; (bitsRemaining - <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 27</span>                     curByte = (<span style="color: rgba(0, 0, 255, 1)">byte</span>)(curByte |<span style="color: rgba(0, 0, 0, 1)"> mask);
</span><span style="color: rgba(0, 128, 128, 1)"> 28</span>                     bitsRemaining -= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 29</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)"> 30</span>               <span style="color: rgba(0, 0, 255, 1)">else</span>
<span style="color: rgba(0, 128, 128, 1)"> 31</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 32</span>                     mask = cValue &gt;&gt; (<span style="color: rgba(128, 0, 128, 1)">5</span> -<span style="color: rgba(0, 0, 0, 1)"> bitsRemaining);
</span><span style="color: rgba(0, 128, 128, 1)"> 33</span>                     curByte = (<span style="color: rgba(0, 0, 255, 1)">byte</span>)(curByte |<span style="color: rgba(0, 0, 0, 1)"> mask);
</span><span style="color: rgba(0, 128, 128, 1)"> 34</span>                     returnArray =<span style="color: rgba(0, 0, 0, 1)"> curByte;
</span><span style="color: rgba(0, 128, 128, 1)"> 35</span>                     curByte = (<span style="color: rgba(0, 0, 255, 1)">byte</span>)(cValue &lt;&lt; (<span style="color: rgba(128, 0, 128, 1)">3</span> +<span style="color: rgba(0, 0, 0, 1)"> bitsRemaining));
</span><span style="color: rgba(0, 128, 128, 1)"> 36</span>                     bitsRemaining += <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 37</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)"> 38</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 39</span>
<span style="color: rgba(0, 128, 128, 1)"> 40</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (arrayIndex !=<span style="color: rgba(0, 0, 0, 1)"> byteCount)
</span><span style="color: rgba(0, 128, 128, 1)"> 41</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 42</span>               returnArray =<span style="color: rgba(0, 0, 0, 1)"> curByte;
</span><span style="color: rgba(0, 128, 128, 1)"> 43</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 44</span>
<span style="color: rgba(0, 128, 128, 1)"> 45</span>             <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> returnArray;
</span><span style="color: rgba(0, 128, 128, 1)"> 46</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 47</span>
<span style="color: rgba(0, 128, 128, 1)"> 48</span>         <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ToString(<span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] input)
</span><span style="color: rgba(0, 128, 128, 1)"> 49</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 50</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (input == <span style="color: rgba(0, 0, 255, 1)">null</span> || input.Length == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 51</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 52</span>               <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> ArgumentNullException(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">input</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 53</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 54</span>
<span style="color: rgba(0, 128, 128, 1)"> 55</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> charCount = (<span style="color: rgba(0, 0, 255, 1)">int</span>)Math.Ceiling(input.Length / 5d) * <span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 56</span>             <span style="color: rgba(0, 0, 255, 1)">char</span>[] returnArray = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">char</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 57</span>
<span style="color: rgba(0, 128, 128, 1)"> 58</span>             <span style="color: rgba(0, 0, 255, 1)">byte</span> nextChar = <span style="color: rgba(128, 0, 128, 1)">0</span>, bitsRemaining = <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 59</span>             <span style="color: rgba(0, 0, 255, 1)">int</span> arrayIndex = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 60</span>
<span style="color: rgba(0, 128, 128, 1)"> 61</span>             <span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">byte</span> b <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> input)
</span><span style="color: rgba(0, 128, 128, 1)"> 62</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 63</span>               nextChar = (<span style="color: rgba(0, 0, 255, 1)">byte</span>)(nextChar | (b &gt;&gt; (<span style="color: rgba(128, 0, 128, 1)">8</span> -<span style="color: rgba(0, 0, 0, 1)"> bitsRemaining)));
</span><span style="color: rgba(0, 128, 128, 1)"> 64</span>               returnArray =<span style="color: rgba(0, 0, 0, 1)"> ValueToChar(nextChar);
</span><span style="color: rgba(0, 128, 128, 1)"> 65</span>
<span style="color: rgba(0, 128, 128, 1)"> 66</span>               <span style="color: rgba(0, 0, 255, 1)">if</span> (bitsRemaining &lt; <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 67</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)"> 68</span>                     nextChar = (<span style="color: rgba(0, 0, 255, 1)">byte</span>)((b &gt;&gt; (<span style="color: rgba(128, 0, 128, 1)">3</span> - bitsRemaining)) &amp; <span style="color: rgba(128, 0, 128, 1)">31</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 69</span>                     returnArray =<span style="color: rgba(0, 0, 0, 1)"> ValueToChar(nextChar);
</span><span style="color: rgba(0, 128, 128, 1)"> 70</span>                     bitsRemaining += <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 71</span> <span style="color: rgba(0, 0, 0, 1)">                }
</span><span style="color: rgba(0, 128, 128, 1)"> 72</span>
<span style="color: rgba(0, 128, 128, 1)"> 73</span>               bitsRemaining -= <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 74</span>               nextChar = (<span style="color: rgba(0, 0, 255, 1)">byte</span>)((b &lt;&lt; bitsRemaining) &amp; <span style="color: rgba(128, 0, 128, 1)">31</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 75</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 76</span>
<span style="color: rgba(0, 128, 128, 1)"> 77</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (arrayIndex !=<span style="color: rgba(0, 0, 0, 1)"> charCount)
</span><span style="color: rgba(0, 128, 128, 1)"> 78</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 79</span>               returnArray =<span style="color: rgba(0, 0, 0, 1)"> ValueToChar(nextChar);
</span><span style="color: rgba(0, 128, 128, 1)"> 80</span>               <span style="color: rgba(0, 0, 255, 1)">while</span> (arrayIndex != charCount) returnArray = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">=</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 81</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 82</span>
<span style="color: rgba(0, 128, 128, 1)"> 83</span>             <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">(returnArray);
</span><span style="color: rgba(0, 128, 128, 1)"> 84</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 85</span>
<span style="color: rgba(0, 128, 128, 1)"> 86</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span> CharToValue(<span style="color: rgba(0, 0, 255, 1)">char</span><span style="color: rgba(0, 0, 0, 1)"> c)
</span><span style="color: rgba(0, 128, 128, 1)"> 87</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)"> 88</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> value = (<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)c;
</span><span style="color: rgba(0, 128, 128, 1)"> 89</span>
<span style="color: rgba(0, 128, 128, 1)"> 90</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (value &lt; <span style="color: rgba(128, 0, 128, 1)">91</span> &amp;&amp; value &gt; <span style="color: rgba(128, 0, 128, 1)">64</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 91</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 92</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> value - <span style="color: rgba(128, 0, 128, 1)">65</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 93</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 94</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (value &lt; <span style="color: rgba(128, 0, 128, 1)">56</span> &amp;&amp; value &gt; <span style="color: rgba(128, 0, 128, 1)">49</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 95</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)"> 96</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> value - <span style="color: rgba(128, 0, 128, 1)">24</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 97</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)"> 98</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (value &lt; <span style="color: rgba(128, 0, 128, 1)">123</span> &amp;&amp; value &gt; <span style="color: rgba(128, 0, 128, 1)">96</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 99</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">100</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> value - <span style="color: rgba(128, 0, 128, 1)">97</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">101</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">102</span>
<span style="color: rgba(0, 128, 128, 1)">103</span>             <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> ArgumentException(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Character is not a Base32 character.</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">c</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">104</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">105</span>
<span style="color: rgba(0, 128, 128, 1)">106</span>         <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">char</span> ValueToChar(<span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)"> b)
</span><span style="color: rgba(0, 128, 128, 1)">107</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">108</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (b &lt; <span style="color: rgba(128, 0, 128, 1)">26</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">109</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">110</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> (<span style="color: rgba(0, 0, 255, 1)">char</span>)(b + <span style="color: rgba(128, 0, 128, 1)">65</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">111</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">112</span>
<span style="color: rgba(0, 128, 128, 1)">113</span>             <span style="color: rgba(0, 0, 255, 1)">if</span> (b &lt; <span style="color: rgba(128, 0, 128, 1)">32</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">114</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">115</span>               <span style="color: rgba(0, 0, 255, 1)">return</span> (<span style="color: rgba(0, 0, 255, 1)">char</span>)(b + <span style="color: rgba(128, 0, 128, 1)">24</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">116</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">117</span>
<span style="color: rgba(0, 128, 128, 1)">118</span>             <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> ArgumentException(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Byte is not a value Base32 value.</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">b</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">119</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">120</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">121</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>&nbsp;</p>
</div>
<h2>总结</h2>
<h3>需要注意的坑</h3>
<div>
<p>移动端下载的认证器的秘钥key是通过base32转码得到的,而程序端是直接输入源码。</p>
<p>如原秘钥为xeon997@foxmail.com生成的base32码PBSW63RZHE3UAZTPPBWWC2LMFZRW63I=才是移动端需要输入的秘钥。</p>
<p>在网上找了很多资料没有发现关于C#的案例,所以在此记录一下自己遇到的坑,让更多的人能够跳过这个坑。</p>
<p>案例地址:</p>
<p>git:https://github.com/CN-Yi/GoogleAuthenticator</p>
<p>gitee:https://gitee.com/hsyi/GoogleAuthenticator</p>
<p>在此感谢提供学习资料的大神们,如果有错误的地方欢迎留言。</p>
<div>&nbsp;</div>
</div><br><br>
来源:https://www.cnblogs.com/hsyi/p/11054869.html
頁: [1]
查看完整版本: Google Authenticator(谷歌身份验证器)C#版