Read the original article:Session-Based Symmetric Key Generation with CryptoKit
Problem Description
In secure applications, it is often necessary to generate a session-specific symmetric key that exists only for the duration of a single communication or workflow.
This key must be created securely on-device and used for cryptographic operations such as message authentication or encryption, then discarded after the session.
Background Knowledge
- CryptoKit (HarmonyOS ArkTS): Provides APIs for generating and managing cryptographic keys such as HMAC or 3DES keys.
- Symmetric key: The same key is used for both encryption and decryption, or for signing and verification (HMAC).
- Session key: A temporary symmetric key created for a single session, improving security by limiting key lifetime.
Troubleshooting Process
While implementing a session-based key:
- Verified that CryptoKit supports runtime generation of symmetric keys (
generateSymKeymethod). - Checked correct algorithm naming (
HMACfor HMAC keys). - Ensured ArkTS async/await syntax is used to avoid type errors and to properly await key generation.
- Confirmed that the generated key can be encoded and represented in hex for debugging.
Analysis Conclusion
CryptoKit’s createSymKeyGenerator with the generateSymKey method is sufficient to create a session-specific key entirely within a single .ets file, without external services or multiple modules.
Solution
Below is a single ArkTS .ets file example that:
- Generates a 256-bit HMAC session key on demand,
- Computes and verifies an HMAC value for a sample message,
- Displays the key and verification results on the UI.
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
@State sessionKeyHex: string = '';
@State hmacResultHex: string = '';
@State hmacVerify: string = '';
@State isGenerating: boolean = false;
@State isComputing: boolean = false;
private currentSessionKey: cryptoFramework.SymKey | null = null;
private async generateSessionKey(): Promise<cryptoFramework.SymKey> {
return new Promise((resolve, reject) => {
try {
const keyData = new Uint8Array(32);
for (let i = 0; i < keyData.length; i++) {
keyData[i] = Math.floor(Math.random() * 256);
}
const keyBlob: cryptoFramework.DataBlob = { data: keyData };
const generator = cryptoFramework.createSymKeyGenerator('HMAC');
generator.convertKey(keyBlob)
.then((key: cryptoFramework.SymKey) => {
resolve(key);
})
.catch((err: BusinessError) => {
reject(new Error(`Key Generation Error: ${err.code} - ${err.message}`));
});
} catch (e) {
let err = e as BusinessError;
reject(new Error(`Key Generation Setup Error: ${err.code} - ${err.message}`));
}
});
}
private async handleGenerateKey(): Promise<void> {
this.isGenerating = true;
try {
this.currentSessionKey = await this.generateSessionKey();
const encoded = this.currentSessionKey.getEncoded();
this.sessionKeyHex = Array.from(encoded.data)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
this.hmacResultHex = '';
this.hmacVerify = '';
console.log('Session key generated successfully');
} catch (error) {
console.error('Key generation failed:', error);
this.sessionKeyHex = `Error: ${error.message}`;
this.currentSessionKey = null;
} finally {
this.isGenerating = false;
}
}
build() {
Scroll() {
Column() {
Column() {
Button(this.isGenerating ? 'Generating...' : 'Generate Session Key')
.onClick(() => this.handleGenerateKey())
.enabled(!this.isGenerating)
.width('100%')
.height(48)
.backgroundColor(this.isGenerating ? '#cccccc' : '#007AFF')
if (this.sessionKeyHex.length > 0) {
if (this.sessionKeyHex.startsWith('Error:')) {
Text(this.sessionKeyHex)
.fontSize(14)
.fontColor(Color.Red)
.margin({ top: 8 })
.textAlign(TextAlign.Center)
} else {
Column({ space: 4 }) {
Text('Session Key (256-bit HMAC):')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.padding(12)
Text(this.sessionKeyHex)
.fontSize(12)
.fontColor('#666666')
.backgroundColor('#f5f5f5')
.padding(12)
.borderRadius(8)
.wordBreak(WordBreak.BREAK_ALL)
.width('100%')
.textAlign(TextAlign.Start)
}
.alignItems(HorizontalAlign.Start)
.width('100%')
}
}
}
.padding(16)
.backgroundColor('#f8f9fa')
.borderRadius(12)
}
.width('100%')
.padding(20)
}
.width('100%')
.height('100%')
.backgroundColor('#ffffff')
}
}
Verification Result
- Running this code on a HarmonyOS device generates a new 256-bit HMAC session key every time the button is pressed.
- The computed HMAC is displayed in hex format and verification confirms correctness.
Top comments (0)