Flipper Zero 凯撒密码(Caesar Cipher)应用实战指南:算法原理、GUI 实现与 fbt 编译
【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper
本文以 Flipper 仓库中 grnch/caesarcipher 应用为核心,完整讲解这个运行在 Flipper Zero 屏幕上的凯撒密码移位器:从设备上的输入与输出操作流程,到caesar_cipher.c中的字符位移算法与双视图 GUI 架构,再到通过fbt构建 FAP 插件的完整方法。读完本文,你既能立刻上手使用该工具对任意文本做 25 种位移的暴力枚举,也能理解一个典型 Flipper 外部应用(External App)的代码组织方式。
一、这是什么:一个运行在 Flipper Zero 上的凯撒密码移位器
凯撒密码(Caesar Cipher)是最古老的替换式加密算法之一:明文中的每个字母沿字母表向后(或向前)移动固定位数 N,即得到密文。Flipper Zero 上的这款 Caesar Cipher 应用,正是把这一经典算法搬上了 128×64 的单色屏幕。
它位于仓库的 Applications/Official/source-OLDER/grnch/caesarcipher/ 目录下,作者在 README 中将其定位为:
A caesar cipher encoder for the Flipper Zero device.
需要特别说明的是它的实际工作方式:从源码实现看,它并非让你选择某个固定的位移数,而是一次性把输入文本按 rot = 1 到 25 的全部 25 种位移都算出来并逐行显示(详见下文"算法实现"一节)。这意味着:
- 当你加密时,25 行输出中的每一行都是输入明文在某个密钥下的密文,你只需找到目标密钥那一行即可;
- 当你解密时,无论密文用了哪个位移,由于 25 种可能密钥被全部枚举出来,人眼扫一眼即可挑出语义通顺的明文——这是一种朴素但有效的暴力破解方式。
README 将其描述为 encoder,同时在使用说明中又要求"输入你的密文(ciphertext)",二者并不矛盾:正是因为全量输出了 25 种位移,它天然就是一个加解密两用的"穷举移位器"。你可以在 ReadMe.md 中看到整个仓库对这种玩具/工具类 Flipper 应用的收录定位。
二、设备上的使用流程
原文档的使用说明非常精简,但它是操作的唯一权威依据,完整继承如下,并补充设备交互细节:
- 启动应用:在 Flipper Zero 上进入应用列表(该应用类别为 Misc,见后文
application.fam),打开 Caesar Cipher。 - 输入文本:使用屏幕上的虚拟键盘(on-screen keyboard)逐字符输入你要处理的文本。上图中的第一张截图即为输入界面,顶部标题为
Input,键盘布局为 qwerty 三行字母加数字行,并提供下划线_与回退删除键。 - 空格替换为下划线:由于屏幕键盘没有空格键,所有空格必须用下划线
_代替。这是使用该应用最容易踩的坑——如果密文中含有空格,请先手动替换为_再输入。 - 按 Save 生成结果:输入完成后按下
Save按钮,应用会立即计算 25 种位移并切换到输出界面。 - 滚动查看输出:输出界面(第二张截图)以多行文本展示结果,右侧有滚动条,可上下滚动逐行查看所有位移结果。
从应用内截图可以直观验证整个流程:输入Syucore_mreb_uf_njrfbzr(这是一段 ROT13 处理过的文本),输出列表中就出现了FLIPPER_ZERO_IS_AWESO...这样语义清晰的明文行——这正是 rot=13 那一行命中的结果。
三、核心算法实现源码解析
应用的全部逻辑都集中在一个单文件 caesar_cipher.c 中,算法部分由两个静态函数构成。
3.1 输入规范化:string_to_uppercase
static void string_to_uppercase(char* input) { int i; for(i = 0; input[i] != '\0'; i++) { if(input[i] >= 'a' && input[i] <= 'z') { input[i] = input[i] - 32; } else { input[i] = input[i]; } } }这段代码(caesar_cipher.c)在生成输出前把输入中的全部小写字母转换为大写:ASCII 中小写字母比对应大写字母大 32,因此input[i] - 32即完成小写转大写。非字母字符原样保留。这一步保证了后续位移运算只需要处理A–Z一个连续区间。
3.2 位移生成核心:build_output
static void build_output(char* input, char* output) { int out = 0; for(int rot = 1; rot < 26; rot++) { int in; for(in = 0; input[in] != '\0'; in++) { if(input[in] >= 'A' && input[in] <= 'Z') { output[out] = 65 + (((input[in] - 65) + rot) % 26); } else { output[out] = input[in]; } out++; } output[out] = '\n'; out++; } output[out] = '\0'; }这段代码(caesar_cipher.c)是整个应用的计算核心,逐行拆解如下:
- 外层循环
rot从 1 遍历到 25,恰好覆盖凯撒密码全部 25 种非平凡位移(rot=0 等于原文,无意义,故被跳过)。 - 内层循环逐字符处理输入:对于落在
A(65) 到Z(90) 区间内的字母,执行65 + ((字符 - 65 + rot) % 26)的取模运算,实现字母环上的循环移位——加 26 后自然回绕到字母表开头(如Z位移 1 得到A)。 - 非字母字符(下划线、数字、标点等)不做位移,原样复制到输出,这正是前面要求"空格用下划线代替"能在输出中保持语义可读的原因。
- 行分隔:每一行位移结果末尾写入
\n换行,最终以\0终止字符串。
由此,输入 N 个字符,输出即为25行、每行 N 个字符(加换行)的完整枚举。输出缓冲区的尺寸也因此被精心设计为char output[(TEXT_BUFFER_SIZE * 26) + (26)](caesar_cipher.c):25 行 × 每行最多 256 字符,加上每行 1 个换行与结尾的\0,即256×26 + 26,正好不越界。
3.3 关键输入约束
- 输入缓冲区
TEXT_BUFFER_SIZE定义为 256(caesar_cipher.c),即单次最多处理 255 个可见字符,超出部分会被截断。 - 仅支持 ASCII 大写字母的位移,中文、带重音字母等均不在算法处理范围内(会原样保留在输出中)。
- 由于是纯枚举输出,应用本身不涉及任何密钥选择、频率分析或自动判定明文——"哪一行是正确的"完全靠肉眼判断。
四、GUI 架构:TextInput + TextBox 双视图
该应用的界面层是理解 Flipper 官方 GUI 框架(gui模块)的一个极简范例。其状态结构如下:
typedef struct { ViewDispatcher* view_dispatcher; TextInput* text_input; TextBox* text_box; char input[TEXT_BUFFER_SIZE]; char output[(TEXT_BUFFER_SIZE * 26) + (26)]; // linebreaks } CaesarState;(caesar_cipher.c)
应用采用典型的ViewDispatcher(视图调度器)架构,注册了两个视图:
| 视图 ID | GUI 模块 | 用途 | 注册代码 |
|---|---|---|---|
| 0 | TextInput | 屏幕键盘输入 | caesar_cipher.c |
| 1 | TextBox | 多行结果展示 | caesar_cipher.c |
整个生命周期在入口函数caesar_cipher_app()(caesar_cipher.c)中完成,关键节点如下:
- 分配状态与互斥锁:
malloc一个CaesarState,并通过init_mutex创建值为该结构体的ValueMutex,用于保护跨视图共享的输入/输出缓冲区(失败时返回 255)。 - 注册输入回调:
text_input_set_result_callback把text_input_callback绑定到 TextInput,同时传入状态互斥锁与输入缓冲区指针;text_input_set_header_text设置输入页标题为"Input"。 - 获取 GUI 记录:通过
furi_record_open("gui")打开系统 GUI 服务。 - 挂载视图调度器:
view_dispatcher_enable_queue启用事件队列,随后将两个视图注册到 dispatcher,并通过view_dispatcher_attach_to_gui(..., ViewDispatcherTypeFullscreen)以全屏方式挂载到 GUI。 - 事件回调:
back_event_callback响应返回键,调用view_dispatcher_stop结束事件循环;text_input_callback则承担真正的"计算+跳转"职责。 - 启动与清理:
view_dispatcher_run进入事件循环;退出后依次关闭 GUI 记录、删除互斥锁、释放视图与状态内存。
其中最关键的是回调函数text_input_callback(caesar_cipher.c),它在用户按下 Save 后被触发,执行完整的数据流:
static void text_input_callback(void* ctx) { CaesarState* caesar_state = acquire_mutex((ValueMutex*)ctx, 25); FURI_LOG_D("caesar_cipher", "Input text: %s", caesar_state->input); // this is where we build the output. string_to_uppercase(caesar_state->input); FURI_LOG_D("caesar_cipher", "Upper text: %s", caesar_state->input); build_output(caesar_state->input, caesar_state->output); text_box_set_text(caesar_state->text_box, caesar_state->output); view_dispatcher_switch_to_view(caesar_state->view_dispatcher, 1); release_mutex((ValueMutex*)ctx, caesar_state); }即:加锁 → 获取输入 → 转大写 → 枚举 25 种位移 → 把结果文本设置进 TextBox → 切换到视图 1 → 解锁。其中FURI_LOG_D会通过 USB/蓝牙串口输出调试日志(Input text:与Upper text:),便于在开发阶段观察数据流。text_box_set_font(..., TextBoxFontText)在初始化时被调用(caesar_cipher.c),保证输出使用等宽文本字体以对齐每一行。
五、应用元数据:application.fam
Flipper 官方 SDK 使用.fam(Flipper Application Manifest)文件声明应用构建信息,本应用的 application.fam 内容如下:
App( appid="Caesar_Cipher", name="Caesar Cipher", apptype=FlipperAppType.EXTERNAL, entry_point="caesar_cipher_app", cdefines=["APP_CAESAR_CIPHER"], requires=[ "gui", ], stack_size=2 * 1024, fap_icon="caesar_cipher_icon.png", fap_category="Misc", order=20, )各字段含义与影响:
apptype=FlipperAppType.EXTERNAL:声明这是一个外部应用(FAP,Flipper Application Package),以.fap文件形式分发,运行在独立的用户空间进程中,无需刷入固件。entry_point="caesar_cipher_app":指定应用入口函数,与源码中的int32_t caesar_cipher_app()一一对应。requires=["gui"]:声明依赖 GUI 系统服务,对应源码中furi_record_open("gui")的使用。stack_size=2 * 1024:为该应用分配 2 KB 任务栈空间。这个数值对仅有少量局部数组和循环的应用足够;如果未来把TEXT_BUFFER_SIZE大幅调大并在栈上放置大数组,则需要同步考虑增加该值。fap_category="Misc":决定应用在 Flipper 应用菜单中的分类归属,因此启动应用时应在"杂项"类别下查找。fap_icon="caesar_cipher_icon.png":指定应用图标,即同目录下的 caesar_cipher_icon.png。order=20:影响应用在同类列表中的排序位置。cdefines=["APP_CAESAR_CIPHER"]:编译期宏定义,可用于条件编译。
六、编译与构建
在 Flipper Zero 官方固件 SDK 环境中,编译本应用只需在固件仓库根目录执行:
./fbt firmware_caesar_cipher该命令(源自 README.md 的 Compiling 一节)由 Flipper 的构建工具fbt(Flipper Build Tool)执行。由于apptype为 EXTERNAL,构建产物是一个独立.fap文件;将其拷贝到 Flipper Zero 的 SD 卡对应应用目录后,即可在设备菜单中启动。仓库中同属 grnch 系列的 minesweeper、tuning_fork 等应用也沿用了./fbt firmware_<app>的同类构建约定,可作为交叉参考。
七、限制与可扩展方向
基于对源码的分析,可以总结出该应用当前的设计边界,这也是未来二次开发(fork)时最值得动手的地方:
- 纯枚举、无智能识别:25 行输出全部交给肉眼筛选,不提供频率分析或词典匹配来自动标出最可能的明文;
- 输入约束多:空格必须替换为
_、仅支持大写 ASCII 字母、单次输入上限 255 字符,交互体验仍显"痛苦"(README 原话是 "painfully input your ciphertext"); - 无密钥选择功能:不能指定固定 rot 只输出一行,也不能直接进行"解密方向"(即
-rot)的定向换算——虽然 25 行全量枚举在功能上已覆盖所有情况。
如果要在此之上做增强,可从三处入手:在build_output中增加 rot 选择与反向位移分支;在 GUI 层引入更多视图(如结果行选择与复制);或为TEXT_BUFFER_SIZE提供运行时可调能力并同步调整输出缓冲区尺寸公式。
八、小结
Caesar Cipher 应用麻雀虽小,五脏俱全:它完整展示了 Flipper Zero 外部应用从"屏幕键盘取输入 → 核心算法处理 → 多行文本展示"的典型数据流,覆盖了furi记录系统、ValueMutex互斥、ViewDispatcher双视图调度、TextInput/TextBoxGUI 模块,以及application.fam元数据声明与fbt构建这一整条开发链路。无论你是想在设备上快速破解一段经典凯撒密文,还是想以此为模板编写自己的第一个 Flipper 应用,这份源码与本文的对照分析都是很好的起点。
【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考