V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
3dwelcome
V2EX  ›  程序员

友情联动:发支付宝口令红包,欢迎大家破解.

  •  
  •   3dwelcome · 2021-05-14 11:36:46 +08:00 · 6334 次点击
    这是一个创建于 1050 天前的主题,其中的信息可能已经有所发展或是发生改变。

    昨天有个帖子: https://www.v2ex.com/t/776529 前端加密让大家破解 AES 加密红包,这太离谱了。

    我把 AES 算法去掉,现阶段的计算机要破译几乎不可能。改成了最简单的 XOR 加密,也放入了口令红包,欢迎大家破解。

    规则如下:

    1. 支付宝口令红包是纯数字的 0~9, 长度固定为 8

    2. password 明文密码被限定为 0~9, a~z, A~Z 这个范围内,无特殊字符,无中文和符号。

    3. 为了便于校验结果是否有效,支付宝口令累加起来的数字,是 45 。(比如口令是 12345678, 累加值就是 1+2+3+4+5+6+7+8=36)

    4. 核心解密函数就一行,password 是不知道的,是前端 input 用户输入。

    var str = "WmXOsVFG";
    var pass = "????????";
    var num = "";

    for (var i=0;i<pass.length;i++)
    num += String.fromCharCode(pass.charCodeAt(i) ^ str.charCodeAt(i));

    57 条回复    2021-05-15 16:55:34 +08:00
    adm7n
        1
    adm7n  
       2021-05-14 12:43:29 +08:00
    算出来 pass=oZozKoww, num=87758910,测试发现不对
    3dwelcome
        2
    3dwelcome  
    OP
       2021-05-14 12:58:02 +08:00
    @adm7n 这题其实是无解的,暴力算下来,排列组合后,总共有 36 万种口令红包的可能性。我发的红包,只是其中之一。

    比如 87758910 和 87758901(pass=oZozKovv),数字累加起来都是 45 。

    很多人都依靠高强度加密算法,我想说,没密钥,连最简单 XOR 都不好破解。
    no1xsyzy
        3
    no1xsyzy  
       2021-05-14 13:28:50 +08:00   ❤️ 1
    主要是通常的明文不是毫无意义的随机数,而且密钥不太可能跟明文一样长。

    比如保持 8 位,模仿 virginia 循环 XOR,并且明文是 12 个不同的目前存活的人的生日,有非常高的概率破解出来。
    sillydaddy
        4
    sillydaddy  
       2021-05-14 13:32:36 +08:00
    同意 3 楼。
    看看我设计的“文字指纹”是怎么惨被差分攻击破解的:( /t/774059 )
    3dwelcome
        5
    3dwelcome  
    OP
       2021-05-14 13:41:15 +08:00
    @no1xsyzy "而且密钥不太可能跟明文一样长。"

    密钥长度可以用种子 SEED 加上程序生成,来实现和明文一样长。

    这点技术上问题不大,有那种程序生成很长,又不重复的序列。
    3dwelcome
        6
    3dwelcome  
    OP
       2021-05-14 13:47:25 +08:00
    @sillydaddy “有没有办法防止 app 内资源被提取呢?”

    如果我是你,就把本地资源加密,密钥别写进程序里,在用户登录的过程中,服务器动态获取,动态解压资源。

    这样的话,离线资源是没办法被破解的。
    matrix67
        7
    matrix67  
       2021-05-14 13:48:08 +08:00   ❤️ 4
    这让我想起了之前《每个社区总有一个神贴,我被他浪费了整整一个小时。。》( https://www.v2ex.com/t/145275 )这个帖子里面提到的彩虹表事件。

    2013 年左右就有的。逆向出来送 mpb 。

    http://www.v2ex.com/t/29091
    http://www.v2ex.com/t/29113
    http://www.v2ex.com/t/29184
    no1xsyzy
        8
    no1xsyzy  
       2021-05-14 14:46:42 +08:00
    @3dwelcome 那把它再拉长点,不重复序列转换成向量表,不就是 DES 了嘛(
    加密算法实现上并不复杂(否则根本无法运用,不可能每个语言每个平台都写一遍非常复杂的实现(当然,尽量不要自己实现,你还得保证自己实现得没错)),难点在于构造这个算法,同时还得证明这个算法足够强。
    AoEiuV020
        9
    AoEiuV020  
       2021-05-14 15:00:58 +08:00
    @matrix67 精彩,看的我都差点忘了自己在上班了,
    3dwelcome
        10
    3dwelcome  
    OP
       2021-05-14 15:44:26 +08:00
    @no1xsyzy 在所有的加密算法里,我还是觉得 RSA 加密最优美。

    有随机数 PADDING 的引入,导致每次加密的结果完全不同。

    传统 AES 对称算法,就算优化上天,使用同一个密钥,也不可能每次加密的结果不一样。
    sillydaddy
        11
    sillydaddy  
       2021-05-14 15:53:30 +08:00
    @matrix67 #7
    真是神帖啊。浪费了一个小时,不过看得过瘾,哈哈。
    是不是马甲,每个人都心里有数。
    不过也真巧,正好应了我在 4 楼提到的“文字指纹”——可以把各方的发言找出来,验一验文字指纹就知道了,这事有够无聊,也挺有意思 ( 逃
    blvvet
        12
    blvvet  
       2021-05-14 16:00:12 +08:00   ❤️ 2
    彩虹表事件看完觉得站长好 low
    xloger
        13
    xloger  
       2021-05-14 16:07:05 +08:00
    @matrix67 #7 看完了,挺有意思的。然后也看到了后续的一些质疑与回应。不知道这事后面有没有公论,但我倾向于认为这事还挺真实的。

    不知道各位如果要生成一个字符串的 MD5 会用什么方式?我的话,固然是可以用集成好的 Guava 本地跑一次结果,但我更大概率会用我装的 Chrome 插件 “前端工具箱” 或者我常用的一个工具网站 https://tool.oschina.net/ 。而这两个都可能存在会将我的 md5 计算保存到彩虹表中。

    第二贴里有人质疑破解者哪能那么巧黑到发帖者的电脑,说也是一起炒作的。这让我想到了个问题,两个骰子都是 6 点的概率是多少?大家都会说 1/36 吧。但是实际上两个 1,两个 2 这样的,让人感觉是巧合的例子,那就是 1/6 了。如果发帖者没有这个漏洞被黑,也可能有下一个漏洞被黑,最后展现出来的好像很巧合实际上并不是。

    后续还有人也试图发个 md5 值和给出规律,让破解者来验证。这种行为是毫无意义的,所谓的自证清白很难。因为如果回应了这个帖子,那又会有人说这是站长联合这个质疑者的炒作,反串白。

    总之,到底是不是真的对我已经不重要了,这个鱼摸得很值很开心。马上就能下班了!
    GeruzoniAnsasu
        14
    GeruzoniAnsasu  
       2021-05-14 16:09:46 +08:00
    @sillydaddy 咋老惦记你的文字指纹……论文查重就是文字指纹,你品
    xloger
        15
    xloger  
       2021-05-14 16:13:36 +08:00
    @blvvet #12 人是会成长的,技术也是会成长的。谁也不可能一开始对计算机的每个体系都很了解啊,很多你以为的常识并不是常识。
    比如二进制是基础是吧,那今天还有个贴讲了 XOR 加密,也就是通过异或运算进行的,为啥异或能做到这些呢,hash 计算中也运用到了 XOR 进行搅拌,为什么选用 XOR 进行这些呢?我没有杠的意思啊,我是最近恰好在补一些相关的知识。这对基础好的人来说可能也是常识,但反正我现在还没看懂 hash 的具体实现。

    而回头看几年前的自己,如果觉得 low 是很正常的,说明自己进步了。而这种行为顶多是看看自己,用来看别人就不合适了。
    kop1989
        16
    kop1989  
       2021-05-14 16:35:01 +08:00
    @matrix67 #6

    这个有点意思。
    这几个人写了一大通,最终等于什么也没说。
    lbyo
        17
    lbyo  
       2021-05-14 16:59:15 +08:00

    如果不是炒作,那我觉得这是唯一能解释得通的了
    kop1989
        18
    kop1989  
       2021-05-14 17:07:27 +08:00
    @xloger #11

    如果是以现在的视角,结合当年的情况来看,我更倾向于这件事不是真的。

    1 、过于戏剧化,尤其是大学老师那个。
    2 、成功在碰撞者,表达和立场转变之快令人乍舌,从不可一世的大神一举变成“我朋友”。
    3 、原帖表达有很多不合理之处,最终归结到一个“API”上。
    4 、碰撞出合理结果的速度太快。

    不过楼上说站长的水平问题确实有失偏颇。
    无论是结合当年的 IT 普及水平,IT 中文信息丰富程度,还是 V 站当时的发展需要,我觉得站长当时做出的回复,还是相对合理的。如果我是站长,可能我会更加难掩兴奋的去推波助澜,甚至亲自下场搅局。
    aloxaf
        19
    aloxaf  
       2021-05-14 17:10:52 +08:00
    @3dwelcome #2 异或虽然简单但安全性并不一定差,在密钥随机且长度和明文相等且只使用一次的情况下,也是理论上无法破解的……
    AoEiuV020
        20
    AoEiuV020  
       2021-05-14 17:22:53 +08:00
    @aloxaf 简单意味着爆破效率高,因此安全性差,
    无法破解只是正确解太多而已,
    就像楼主这题,假如正确密码是“fUkyFgwu12”,正确答案是“1836511212”,
    这时候别人跑出来密码是"gUkyFgwu12", 答案是"0836511212", 同样是合理的,但答案是错的,这破解就没有意义,
    AoEiuV020
        21
    AoEiuV020  
       2021-05-14 17:31:29 +08:00
    楼主这个例子可以继续简化一下,xor 都不需要,
    var sum = 87654321;
    var pass = ????????;
    var num = sum - pass;
    num
    已知 pass 是 8 位数字,求 num,
    qq316107934
        22
    qq316107934  
       2021-05-14 17:35:42 +08:00
    @kop1989 同意你的观点,尤其是后面还有不定长随机字符。构建彩虹表也是需要大量时间的,彩虹表只能加速离线搜索速度。
    3dwelcome
        23
    3dwelcome  
    OP
       2021-05-14 18:01:04 +08:00
    @AoEiuV020 “简单意味着爆破效率高,因此安全性差,”

    AES 还能 CPU 加速来着,运行速度极快,但就是没人说过安全性差。

    你这里列举的反面例子里,把 XOR 替换为 AES,还是同样适用的。

    只要 XOR 密钥构建足够长,比如明文长度 100M,密钥长度也是 100M (程序生成无重复序列),那么 XOR 安全性一点都不输给 AES 。
    AoEiuV020
        24
    AoEiuV020  
       2021-05-14 18:11:05 +08:00
    @3dwelcome 可能是对“安全性”的理解不一样吧,
    假设算法中 xor 秘钥长度 100,破解理论需要计算 100w 次,破解需要时间 10 秒,
    而 aes 秘钥长度 16,破解理论需要计算 1w 次,破解需要时间同样 10 秒,
    你认为在这个例子中 xor 安全性和 aes 一样,
    我认为在这个例子中 aes 安全性更高,
    3dwelcome
        25
    3dwelcome  
    OP
       2021-05-14 18:17:47 +08:00
    @AoEiuV020

    代码运行速度慢 = 安全性高?这种思路不对吧,好算法设计就是要运行速度足够快。

    不能说我设计一个加密算法,起名叫乌龟,就很安全,这不科学。

    你说的爆破解,也仅仅针对有唯一解的题目。现实中很多密文解密后,都是一行文字,都不能确认是不是唯一的。
    AoEiuV020
        26
    AoEiuV020  
       2021-05-14 18:22:09 +08:00
    @3dwelcome 不是=,这只是一方面,还有其他因素影响安全性,我只是想描述简单和安全性的联系,是通过爆破效率联系上的,
    AoEiuV020
        27
    AoEiuV020  
       2021-05-14 18:29:12 +08:00
    @3dwelcome 比如 linux 的 su 为了安全,就有故意在密码错误时设置延时,降低响应速度,降低破解效率,提升安全性,这只是一种手段,一条路,肯定不能放弃其他只看这个,
    3dwelcome
        28
    3dwelcome  
    OP
       2021-05-14 18:52:27 +08:00
    @AoEiuV020 手机 SIM 卡 PIN 只要输错三次,直接就锁卡了。

    也没牵涉到任何加密算法,就是极大限度提高黑客的试错成本。

    这样确实是安全性高一些,但个人觉得和算法本身设计,已经没什么关系了。
    pke
        29
    pke  
       2021-05-14 19:32:17 +08:00
    @matrix67 #7 用一小时看完了,了解了一段精彩的历史,不算浪费,比当初参与此种的人甚至节省了很多时间

    不过注意点神贴回复数人都提到 2012 年在挖 btcoin,不知道他们现在怎样了
    skies457
        30
    skies457  
       2021-05-14 19:45:12 +08:00
    科班出身、学过基本密码学的人根本不会出这样毫无意义的题,本质上就是给定序列 A,求解 Ai^Xi=Yi,在没有额外信息下这组式子有无数解,因此枚举 Xi 和枚举 Yi 是一样的,不如直接去试支付宝口令。那么为啥 xor 不适用于需要正经加密的场景呢?因为这些场景往往是有额外信息的,比如破解文本密码经常会用到英语字母的频率,而且生成出来的结果一般是有意义的(比如网络包都有固定的结构或者 header ),所以 xor 加密在大量使用的情况下安全性非常差
    BeautifulSoap
        31
    BeautifulSoap  
       2021-05-14 19:59:01 +08:00
    看了上面彩虹表事件之后,我猛然发现了一个大家都没注意到的有意思的细节,事件时间是 2012 年,站长有个回复:

    Livid:
    曾经我还挖矿的时候,两块 6870 可以每秒 600M 个 SHA1,而 MD5 的复杂度更低


    2012 年之前挖矿的话那肯定是比特币了,不知道站长之后有么有把币卖了,如果没卖的话那难怪 V2EX 能坚持这么多年还没广告
    Mohanson
        32
    Mohanson  
       2021-05-14 20:09:41 +08:00 via Android
    对 xor 感兴趣的话,去搜下 rc4 算法,然后理解它为什么是不安全的以及为什么被弃用
    3dwelcome
        33
    3dwelcome  
    OP
       2021-05-14 20:20:29 +08:00
    @skies457 你说的不就是频率分析攻击吗?

    这些攻击针对的都是定长密钥,对于代码自动生成的无限长密钥,这些 XOR 弱点都不存在。

    可以不回贴,但不要不懂装懂。
    x86
        34
    x86  
       2021-05-14 20:26:23 +08:00
    @lbyo #17 这是当年送 rmbp 的帖子吧
    skies457
        35
    skies457  
       2021-05-14 20:50:39 +08:00 via iPhone
    @3dwelcome 那么请问您要怎么分享这个无限长的密钥呢
    3dwelcome
        36
    3dwelcome  
    OP
       2021-05-14 21:42:33 +08:00
    @skies457 分享无限长的密钥,用的肯定是生成无序数列的代码片段了。

    有了 webasm,几乎什么算法,js 都是能正常运行的。

    你要说在分享过程中,代码片段被中间人截取了,那等于是密钥泄漏。几乎任何加密算法,都没办法在密钥泄漏的情况下,避免被破解。(除了量子加密外)
    lbyo
        37
    lbyo  
       2021-05-14 22:00:46 +08:00
    @x86 是的,今天无意中看到了,还把整个时间线搞出来了,不知道老哥当年有没有看到全程,需要分享吗
    x86
        38
    x86  
       2021-05-14 22:01:43 +08:00
    @lbyo #37 哈哈,我全程看过
    no1xsyzy
        39
    no1xsyzy  
       2021-05-14 22:47:05 +08:00   ❤️ 1
    @3dwelcome #10 目前来说,拿卡牌游戏做比喻
    非对称都是数学的宝石,类似一套操作 OTK 或者北京龙卡回合套路。
    对称大多数是按部就班地处理,类似堆怪堆甲堆 buff
    而哈希则像是捣浆糊的神智错乱,好比把『混沌之球』撕成碎片然后掷向对方半场

    不过 random padding 对称也能做,甚至 hash 也能做(加盐)。

    #25 也有 bcrypt 这种纯粹为了慢设计的算法
    #28 CIA 三方面里面,A 能靠一定错误次数后加锁来保证,而 C 不能靠一定错误次数后加锁来保证
    skies457
        40
    skies457  
       2021-05-14 22:49:22 +08:00
    @3dwelcome https://en.wikipedia.org/wiki/Stream_cipher_attacks 建议读一下这个,你这个 idea 已经被研究几十年了
    lbyo
        41
    lbyo  
       2021-05-14 23:20:45 +08:00   ❤️ 10
    @x86
    哈哈可以再对照一下,真是「神帖」;
    彩虹表事件汇总:

    0xTao 送电脑: http://www.v2ex.com/t/29091
    v2fack “打假”被“打脸”: http://www.v2ex.com/t/29113
    F1r3Sn0w 打假: http://www.v2ex.com/t/29184

    allhack 声明上: http://www.v2ex.com/t/29208
    allhack 声明下: http://www.v2ex.com/t/29251

    时间流逝的很快,一句话概括就是,知道一个 hash 值,我能逆向出来一本红楼梦

    事件延续:
    SunMonnnnkey 挑战赛: https://www.v2ex.com/t/29270
    shad0w 破案: https://www.v2ex.com/t/29304
    F1r3Sn0w 爆出这是“四”簧戏: https://web.archive.org/web/20120415224955/https://www.v2ex.com/t/29316

    知情人士 YiQun2Huo 再爆料:
    https://www.v2ex.com/t/29333
    https://www.v2ex.com/t/29338
    no1xsyzy
        42
    no1xsyzy  
       2021-05-14 23:32:21 +08:00
    @3dwelcome #36 你还是看一下对称加密的基础吧,你说到这个「生成无序数列」其实就是简化版的 DES

    第二个问题是,你的无限长密钥,有多少随机性?
    这里要重新再说明一下「随机程度」的概念:一个数列,有多随机,就是说有多难以预测。这依赖于添加足够的熵
    无论何种内部状态有限的伪随机数算法(换句话说,任何有限状态机),如果不从外部添加熵,经过足够长的耗尽后都必收敛于一个循环。
    至于无限不循环的生成,则依赖于无限大的内部状态也就是无限大的内存。

    另一方面,你难道希望这个「代码片段」是随机生成并分发的?
    定理:是否停机不可能被判定。
    引理:不可能自动确认任何随机生成的代码好坏。
    (指不定随机出了实质等价于 (internal)=>(internal%2==0?internal/2:internal*3+1, f(internal)) 的代码呢?你要能确定好坏就意味着证明或证伪了考拉兹猜想。)
    3dwelcome
        43
    3dwelcome  
    OP
       2021-05-15 00:03:54 +08:00
    @no1xsyzy

    "你的无限长密钥,有多少随机性?"
    你也提到了伪随机数算法的生成品质,决定了最终有多少随机性。

    这里并不需要真正意义上的“无限”,覆盖明文长度就可以。我去查了一下,目前比较新的伪随机数算法 xoshiro256/512/1024,在生成 1 PetaByte 长度中,都没有遇到过重复现象。(show no sign of bias after a petabyte of output, https://xoshiro.di.unimi.it/hwd.php)

    而且可能你不信,我确实有一些特殊算法,可以做到序列完全不重复,以一定小空间的代价,来换取一定大范围的不重复。
    windyskr
        44
    windyskr  
       2021-05-15 00:09:50 +08:00 via Android   ❤️ 1
    @lbyo 精彩啊!
    kingxiangqi
        45
    kingxiangqi  
       2021-05-15 00:21:33 +08:00
    @AoEiuV020 #21

    感觉还能继续简化啊,连加减法都不需要。

    已知口令 8 位整数,数字累加和为 45,求口令。
    3dwelcome
        46
    3dwelcome  
    OP
       2021-05-15 00:25:48 +08:00
    @no1xsyzy "也有 bcrypt 这种纯粹为了慢设计的算法"

    这种就是套着加密名称的 hash 算法,强烈鄙视。挂羊头卖狗肉啊。
    no1xsyzy
        47
    no1xsyzy  
       2021-05-15 00:42:42 +08:00
    @3dwelcome (非 CS ) PRNG 突出一个 garbage in garbage out 。种子的空间是有限的,算法的数量是更有限的。
    如果我拿到了比你种子(序列 S )还多的比特的输出(序列 X ),我能不能通过这个 X 构建出你的 S ?做一个 X->S 的反查表或者相应的彩虹表就行了。
    你可以看下 DES 算法(先不细究 F 函数),它找到了一个现成的源源不断的熵池,来生成这个供 XOR 的序列。

    CSPRNG 不是单单「完全不重复」就能说明的,而是强调不可逆猜和旁猜(包含几种难以一句两句描述清楚的旁猜)。我可以立马搞一个从不重复的算法(真正地永远不重复,这个我在 codegolf 上发过一个蠢问题),但你看到输出就能立刻猜到算法。以下是其产生序列的前 32 个字符:
    0-1-2-3-4-5-6-7-8-9-10-11-12-13-
    ( SICP 1.1 都比这难了)
    至于如果你把数据的保密性寄希望于算法的保密性,我只能说祝你好运了,因为你唯一的保证就是好运。
    no1xsyzy
        48
    no1xsyzy  
       2021-05-15 00:51:42 +08:00
    @3dwelcome cryptography 这是「密码学」大类,哈希甚至签名都是密码学研究的课题。真正意义上的对应的「加密」「解密」英文是 to cipher 和 to decipher 。真要说挂羊头卖狗肉,是 encrypt 和 decrypt 这两个造词 —— 既不分析(单 crypt 是「地下室」的意思),也不屈折( en- de- 这两个不是对应的词头,en- 和 dis- 才是)。
    而且不要跑题,用慢来避免爆破,是在描述一种「有效的折衷」,跟非 22 端口 ssh 一个意思。
    learningman
        49
    learningman  
       2021-05-15 01:02:12 +08:00
    @BeautifulSoap #31 V2EX 一直都有广告,你是不是检查一下你的 adblock 。。。
    sillydaddy
        50
    sillydaddy  
       2021-05-15 10:41:03 +08:00
    @GeruzoniAnsasu
    我贴链接就是为了给自己写的东西引流。。哈哈
    论文查重有点不太一样:抄袭论文的人总是会故意特意打乱原有的论文。但在网上留言的人,应该很少特意去掩饰自己的语言习惯。
    persistz
        51
    persistz  
       2021-05-15 13:35:47 +08:00
    @3dwelcome 拿公钥和对称相比不合适啊,两者存在的目的就完全不一样。
    3dwelcome
        52
    3dwelcome  
    OP
       2021-05-15 13:42:17 +08:00
    @persistz "拿公钥和对称相比不合适啊,两者存在的目的就完全不一样。"

    网上有个叫 RSA Cryptography Specifications 的标准文档( rfc3447 ),里面对 RSA 用途做了详细规范,第一是签名认证,第二是纯加密解密。

    第二种用法知道的人少,大部分都是第一种 HTTPS 里 RSA 签名验证的用途。

    但其实 RSA 是完全可以用于加密数据本体的,就是运行速度会慢一点点。
    miloooz
        53
    miloooz  
       2021-05-15 14:29:01 +08:00
    @matrix67 真的精彩,堪比悬疑大片
    shansing
        54
    shansing  
       2021-05-15 15:37:23 +08:00
    @persistz 拿非对称和对称加密相比倒没什么, @3dwelcome #10 最遗憾的点在于话说得太死。如 @no1xsyzy #39 所说,“random padding 对称也能做”。验证这一点甚至不需要去翻标准文档,找一个齐全的在线工具( http://tool.chacuo.net/cryptaes ),padding 方式多选几次选到 iso10126 就看到效果了。
    3dwelcome
        55
    3dwelcome  
    OP
       2021-05-15 16:01:35 +08:00
    @shansing random padding 几乎就是 RSA 发明的,在算法上,是必备环节。

    而对称算法的 random padding,就是一个可选环节。

    你不能说后来者抄个作业,就变得和原创作者一样强。
    matrix67
        56
    matrix67  
       2021-05-15 16:51:16 +08:00   ❤️ 1
    @lbyo #41 老哥你牛逼!!以后又可以浪费无数人的 1 个小时了(应该不止)
    yeqiaowei321
        57
    yeqiaowei321  
       2021-05-15 16:55:34 +08:00
    请支持国产的 SM2 算法
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2855 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 14:28 · PVG 22:28 · LAX 07:28 · JFK 10:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.