鸿蒙安全密码输入键盘开发指南 原创

进修的泡芙
发布于 2025-6-20 13:45
浏览
0收藏

鸿蒙安全密码输入键盘开发指南

一、系统架构设计

基于HarmonyOS的安全密码输入键盘组件,利用分布式能力实现多设备安全同步:
安全输入:防截屏、随机键盘布局、内存保护

跨设备同步:通过加密通道同步输入状态

统一认证:多设备共享密码输入状态

隐私保护:所有敏感信息仅在安全内存处理

!https://example.com/harmony-secure-keyboard-arch.png

二、核心代码实现
安全键盘服务

// SecureKeyboardService.ets
import distributedData from ‘@ohos.distributedData’;
import window from ‘@ohos.window’;
import crypto from ‘@ohos.security.crypto’;

class SecureKeyboardService {
private static instance: SecureKeyboardService = null;
private dataManager: distributedData.DataManager;
private keyboardWindow: window.Window | null = null;
private secureMemory: SecureMemoryArea;
private keyListeners: KeyListener[] = [];

private constructor() {
this.initDataManager();
this.initSecureMemory();
public static getInstance(): SecureKeyboardService {

if (!SecureKeyboardService.instance) {
  SecureKeyboardService.instance = new SecureKeyboardService();

return SecureKeyboardService.instance;

private initDataManager(): void {

this.dataManager = distributedData.createDataManager({
  bundleName: 'com.example.securekeyboard',
  area: distributedData.Area.GLOBAL,
  isEncrypted: true
});

this.dataManager.registerDataListener('keyboard_sync', (data) => {
  this.handleSyncData(data);
});

private initSecureMemory(): void {

this.secureMemory = new SecureMemoryArea(1024); // 1KB安全内存区域

public async showKeyboard(context: common.UIAbilityContext): Promise<void> {

try {
  // 创建安全窗口
  this.keyboardWindow = await window.create(context, 'secure_keyboard', window.WindowType.TYPE_INPUT_METHOD);
  
  // 设置安全标志
  await this.keyboardWindow.setWindowPrivacyMode(true);
  await this.keyboardWindow.setWindowSecure(true);
  
  // 生成随机键盘布局
  this.generateRandomLayout();
  
  // 加载键盘UI
  await this.keyboardWindow.loadContent('pages/SecureKeyboard');
  
  // 显示键盘
  await this.keyboardWindow.show();
  
  // 同步键盘状态
  this.syncKeyboardState('show');

catch (err) {

  console.error('显示安全键盘失败:', JSON.stringify(err));

}

public async hideKeyboard(): Promise<void> {
if (!this.keyboardWindow) return;

try {
  await this.keyboardWindow.hide();
  await this.keyboardWindow.destroy();
  this.keyboardWindow = null;
  
  // 同步键盘状态
  this.syncKeyboardState('hide');

catch (err) {

  console.error('隐藏安全键盘失败:', JSON.stringify(err));

}

private generateRandomLayout(): void {
const digits = [‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’];

// Fisher-Yates洗牌算法
for (let i = digits.length - 1; i > 0; i--) {
  const j = Math.floor(Math.random() * (i + 1));
  [digits[i], digits[j]] = [digits[j], digits[i]];

// 存储到安全内存

this.secureMemory.store('keyLayout', digits);

public handleKeyPress(key: string): void {

if (key === 'DEL') {
  this.notifyKeyEvent('backspace');
  return;

// 验证键位合法性

const layout = this.secureMemory.retrieve('keyLayout');
if (layout.includes(key)) {
  // 存储到安全内存
  const secureValue = this.secureMemory.process(key);
  this.notifyKeyEvent('input', secureValue);
  
  // 同步按键事件
  this.syncKeyPress(key);

}

private notifyKeyEvent(type: ‘input’ | ‘backspace’, value?: string): void {
this.keyListeners.forEach(listener => {
if (type === ‘input’ && value) {
listener.onKeyInput(value);
else if (type === ‘backspace’) {

    listener.onBackspace();

});

private syncKeyboardState(state: ‘show’ | ‘hide’): void {

this.dataManager.syncData('keyboard_sync', {
  type: 'keyboard_state',
  state: state,
  timestamp: Date.now()
});

private syncKeyPress(key: string): void {

this.dataManager.syncData('keyboard_sync', {
  type: 'key_press',
  key: key,
  timestamp: Date.now()
});

private handleSyncData(data: any): void {

if (!data) return;

switch (data.type) {
  case 'keyboard_state':
    this.handleKeyboardStateChange(data.state);
    break;
  case 'key_press':
    this.handleRemoteKeyPress(data.key);
    break;

}

private handleKeyboardStateChange(state: ‘show’ | ‘hide’): void {
this.keyListeners.forEach(listener => {
listener.onKeyboardStateChange(state);
});
private handleRemoteKeyPress(key: string): void {

this.keyListeners.forEach(listener => {
  listener.onRemoteKeyPress(key);
});

public addKeyListener(listener: KeyListener): void {

if (!this.keyListeners.includes(listener)) {
  this.keyListeners.push(listener);

}

public removeKeyListener(listener: KeyListener): void {
this.keyListeners = this.keyListeners.filter(l => l !== listener);
}

interface KeyListener {
onKeyInput(value: string): void;
onBackspace(): void;
onKeyboardStateChange(state: ‘show’ | ‘hide’): void;
onRemoteKeyPress(key: string): void;
class SecureMemoryArea {

private memory: ArrayBuffer;
private crypto: crypto.Crypto;

constructor(size: number) {
this.memory = new ArrayBuffer(size);
this.crypto = crypto.createCrypto(‘AES256-GCM’);
store(key: string, value: any): void {

const jsonStr = JSON.stringify(value);
const encrypted = this.crypto.encrypt(jsonStr);

// 简化存储逻辑,实际应使用更安全的存储方式
const dataView = new DataView(this.memory);
for (let i = 0; i < encrypted.length; i++) {
  dataView.setUint8(i, encrypted.charCodeAt(i));

}

retrieve(key: string): any {
const dataView = new DataView(this.memory);
const bytes = [];
for (let i = 0; i < this.memory.byteLength; i++) {
const byte = dataView.getUint8(i);
if (byte === 0) break;
bytes.push(byte);
const encrypted = String.fromCharCode(…bytes);

const decrypted = this.crypto.decrypt(encrypted);
return JSON.parse(decrypted);

process(value: string): string {

return this.crypto.encrypt(value);

}

export const keyboardService = SecureKeyboardService.getInstance();

安全键盘UI组件

// SecureKeyboard.ets
import { keyboardService } from ‘./SecureKeyboardService’;

@Component
export struct SecureKeyboard {
@State keyLayout: string[] = [];
@State isActive: boolean = false;

aboutToAppear() {
this.keyLayout = keyboardService.getCurrentLayout();
build() {

Column() {
  // 键盘标题
  Text('安全键盘')
    .fontSize(18)
    .margin({ bottom: 20 })
  
  // 键盘主体
  Grid() {
    ForEach(this.keyLayout, (key) => {
      GridItem() {
        Button(key)
          .width('90%')
          .height(60)
          .fontSize(24)
          .backgroundColor(Color.White)
          .onClick(() => {
            keyboardService.handleKeyPress(key);
          })

.margin(5)

    })

.columnsTemplate(‘1fr 1fr 1fr’)

  .rowsTemplate('1fr 1fr 1fr 1fr')
  .columnsGap(10)
  .rowsGap(10)
  .width('100%')
  .height(300)
  
  // 功能键行
  Row() {
    Button('删除')
      .width('40%')
      .height(50)
      .onClick(() => {
        keyboardService.handleKeyPress('DEL');
      })
    
    Button('确定')
      .width('40%')
      .height(50)
      .margin({ left: 10 })
      .onClick(() => {
        keyboardService.hideKeyboard();
      })

.margin({ top: 20 })

.width(‘100%’)

.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
.onAppear(() => {
  keyboardService.addKeyListener({
    onKeyInput: (value) => {
      console.log('安全输入:', value);
    },
    onBackspace: () => {
      console.log('删除输入');
    },
    onKeyboardStateChange: (state) => {
      this.isActive = state === 'show';
    },
    onRemoteKeyPress: (key) => {
      console.log('远程设备按键:', key);

});

})
.onDisappear(() => {
  keyboardService.removeKeyListener({
    onKeyInput: () => {},
    onBackspace: () => {},
    onKeyboardStateChange: () => {},
    onRemoteKeyPress: () => {}
  });
})

}

密码输入框组件

// PasswordInput.ets
import { keyboardService } from ‘./SecureKeyboardService’;

@Component
export struct PasswordInput {
@State password: string = ‘’;
@State isKeyboardVisible: boolean = false;
@State showPassword: boolean = false;
@State dots: string = ‘’;

build() {
Column() {
// 密码显示区域
Row() {
if (this.showPassword) {
Text(this.password)
.fontSize(24)
.fontWeight(FontWeight.Bold)
else {

      Text(this.dots)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

Button(this.showPassword ? ‘隐藏’ : ‘显示’)

      .width(60)
      .height(30)
      .margin({ left: 10 })
      .onClick(() => {
        this.showPassword = !this.showPassword;
      })

.margin({ bottom: 20 })

  // 输入框
  TextInput({ placeholder: '点击输入密码' })
    .width('80%')
    .height(50)
    .type(InputType.Password)
    .onClick(() => {
      this.toggleKeyboard();
    })
    .enabled(false) // 禁用系统键盘
  
  // 键盘切换按钮
  Button(this.isKeyboardVisible ? '隐藏键盘' : '显示安全键盘')
    .width('80%')
    .height(50)
    .margin({ top: 20 })
    .onClick(() => {
      this.toggleKeyboard();
    })

.width(‘100%’)

.height('100%')
.padding(20)
.onAppear(() => {
  keyboardService.addKeyListener({
    onKeyInput: (value) => {
      this.password += value;
      this.updateDots();
    },
    onBackspace: () => {
      this.password = this.password.slice(0, -1);
      this.updateDots();
    },
    onKeyboardStateChange: (state) => {
      this.isKeyboardVisible = state === 'show';
    },
    onRemoteKeyPress: () => {}
  });
})
.onDisappear(() => {
  keyboardService.removeKeyListener({
    onKeyInput: () => {},
    onBackspace: () => {},
    onKeyboardStateChange: () => {},
    onRemoteKeyPress: () => {}
  });
})

private toggleKeyboard(): void {

const context = getContext(this) as common.UIAbilityContext;

if (this.isKeyboardVisible) {
  keyboardService.hideKeyboard();

else {

  keyboardService.showKeyboard(context);

}

private updateDots(): void {
this.dots = ‘•’.repeat(this.password.length);
}

三、分布式同步实现
设备管理服务

// DeviceManagerService.ets
import distributedDeviceManager from ‘@ohos.distributedDeviceManager’;

class DeviceManagerService {
private static instance: DeviceManagerService = null;
private deviceManager: distributedDeviceManager.DeviceManager;
private availableDevices: distributedDeviceManager.DeviceInfo[] = [];

private constructor() {
this.initDeviceManager();
public static getInstance(): DeviceManagerService {

if (!DeviceManagerService.instance) {
  DeviceManagerService.instance = new DeviceManagerService();

return DeviceManagerService.instance;

private initDeviceManager(): void {

this.deviceManager = distributedDeviceManager.createDeviceManager('com.example.securekeyboard');

// 监听设备状态变化
this.deviceManager.on('deviceStateChange', (data) => {
  this.handleDeviceStateChange(data);
});

// 初始发现设备
this.discoverDevices();

private async discoverDevices(): Promise<void> {

try {
  const devices = await this.deviceManager.getAvailableDeviceList();
  this.availableDevices = devices;

catch (err) {

  console.error('发现设备失败:', JSON.stringify(err));

}

private handleDeviceStateChange(data: any): void {
switch (data.action) {
case ‘add’:
this.availableDevices.push(data.device);
break;
case ‘remove’:
this.availableDevices = this.availableDevices.filter(d => d.deviceId !== data.device.deviceId);
break;
case ‘update’:
const index = this.availableDevices.findIndex(d => d.deviceId === data.device.deviceId);
if (index >= 0) {
this.availableDevices[index] = data.device;
break;

}

public getAvailableDevices(): distributedDeviceManager.DeviceInfo[] {
return […this.availableDevices];
public async connectToDevice(deviceId: string): Promise<boolean> {

try {
  const result = await this.deviceManager.connectDevice(deviceId);
  return result;

catch (err) {

  console.error('连接设备失败:', JSON.stringify(err));
  return false;

}

public async disconnectDevice(deviceId: string): Promise<void> {
try {
await this.deviceManager.disconnectDevice(deviceId);
catch (err) {

  console.error('断开设备连接失败:', JSON.stringify(err));

}

export const deviceService = DeviceManagerService.getInstance();

四、项目配置与权限
权限配置

// module.json5
“module”: {

"requestPermissions": [

“name”: “ohos.permission.INPUT_METHOD_MANAGER”,

    "reason": "安全键盘输入管理"
  },

“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,

    "reason": "同步密码输入状态"
  },

“name”: “ohos.permission.PRIVACY_WINDOW”,

    "reason": "设置隐私窗口"
  },

“name”: “ohos.permission.SECURE_WINDOW”,

    "reason": "设置安全窗口"
  },

“name”: “ohos.permission.ACCESS_DISTRIBUTED_DEVICE_MANAGER”,

    "reason": "发现和连接其他设备"

],

"abilities": [

“name”: “MainAbility”,

    "type": "page",
    "visible": true
  },

“name”: “KeyboardAbility”,

    "type": "page",
    "visible": true

]

}

五、总结与扩展

本安全密码输入键盘实现了以下核心功能:
安全防护:防截屏、随机键盘布局、安全内存处理

跨设备同步:多设备实时同步输入状态

统一认证:支持多设备协同密码输入

隐私保护:所有敏感信息加密处理

扩展方向:
生物识别:集成指纹/面部识别验证

硬件安全:支持TEE/SE硬件级安全

动态策略:根据安全需求动态调整策略

主题定制:支持键盘主题和布局自定义

行为分析:输入行为分析和异常检测

通过HarmonyOS的分布式能力和安全框架,我们构建了一个安全可靠的多设备密码输入解决方案。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐