Skip to content

Add com.codename1.security crypto API + OtpField widget#4994

Merged
shai-almog merged 9 commits into
masterfrom
crypto-security-api
May 21, 2026
Merged

Add com.codename1.security crypto API + OtpField widget#4994
shai-almog merged 9 commits into
masterfrom
crypto-security-api

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

  • Adds a first-party com.codename1.security package (hashes, HMAC, AES, RSA, signatures, JWT, HOTP/TOTP) and a com.codename1.components.OtpField UI widget, so apps no longer need an external cn1lib for routine crypto work.
  • Pure-Java MD5/SHA-1/SHA-2/HMAC produce identical output on every platform. AES/RSA/Signature/SecureRandom route through each port's native crypto provider; the default impl uses java.security via reflection so the simulator and Android work out of the box.
  • iOS port is wired end to end via new Ports/iOSPort/nativeSources/CN1Crypto.{h,m} (CommonCrypto + Security framework) called from IOSNative + IOSImplementation.

What's in the package

Class Purpose
Hash MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 (one-shot + streaming)
Hmac RFC 2104 HMAC, plus constant-time tag comparison
SecureRandom platform CSPRNG with bias-free intBelow / longBelow
Cipher AES (GCM/CBC/ECB) and RSA (OAEP/PKCS#1)
Signature RSA and ECDSA signing + verification
KeyGenerator, KeyPair, SecretKey, PublicKey, PrivateKey key material
Jwt JWT sign/verify for HS, RS, ES families (RFC 7519)
Otp HOTP (RFC 4226) + TOTP (RFC 6238), Google-Authenticator compatible
Base32, Base64Url, CryptoException encodings + error type
com.codename1.components.OtpField segmented OTP input with auto-advance and paste distribution

Impl layer

  • CodenameOneImplementation gains aesEncrypt/Decrypt, rsaEncrypt/Decrypt, cryptoSign/Verify, secureRandomBytes, generateRsaKeyPair, generateSymmetricKey. Default implementation does the work via reflection against java.security/javax.crypto.
  • com.codename1.io.Util exposes narrow public static delegates (Util.secureRandomBytes, Util.aesEncrypt, etc.) that the security package uses. Util.getImplementation() stays package-private — the security package never reaches for the raw impl.
  • iOS port overrides every crypto bridge method in IOSImplementation and routes through new native methods on IOSNative whose C-side implementations live in the new CN1Crypto.{h,m} files in nativeSources/.

Tests

32 new tests under maven/core-unittests/src/test/java/com/codename1/security:

  • HashTest — FIPS 180-4 reference vectors for MD5/SHA-1/SHA-256/SHA-384/SHA-512 + multi-block (1MB) coverage
  • HmacTest — RFC 4231 vectors (cases 1, 2 SHA-256/512, case 6 long key)
  • OtpTest — RFC 4226 appendix D and RFC 6238 appendix B vectors, plus drift/tolerance assertions and Base32 round-trip
  • JwtTest — round-trip + canonical jwt.io HS256 example + malformed/none-alg handling
  • CipherSignatureTest — AES-GCM round-trip + tamper detection, AES-CBC, RSA-OAEP, RSA-SHA-256 sign/verify with tampering, JWT RS256 round-trip, SecureRandom checks

Developer guide

New "Cryptographic primitives" section in docs/developer-guide/security.asciidoc with runnable examples for every entry point, an algorithm-constant reference table, and recommended-key-size guidance.

Test plan

  • mvn -pl core compile -DskipTests succeeds
  • cd maven/core-unittests && mvn test -Dtest='HashTest,HmacTest,OtpTest,JwtTest,CipherSignatureTest' → 32/32 pass
  • mvn -pl ios -am install -Dmaven.javadoc.skip=true -DskipTests succeeds
  • Build a sample iOS app end-to-end (Xcode) and exercise Hash, Hmac, Otp, AES-GCM round-trip, RSA sign/verify against the new native bridge
  • asciidoctor docs/developer-guide/developer-guide.asciidoc renders without errors

🤖 Generated with Claude Code

shai-almog and others added 3 commits May 21, 2026 16:14
Introduces a first-party cryptography API in com.codename1.security so apps
no longer need an external cn1lib for routine hashing, MAC, encryption,
signing, JWT, and OTP work. Pure-Java algorithms produce identical output
on every platform; AES/RSA/Signature/SecureRandom route through each port's
native crypto provider.

New public API:
- Hash         MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 (pure Java)
- Hmac         RFC 2104 + constant-time compare (pure Java)
- SecureRandom platform CSPRNG with bias-free intBelow/longBelow
- Cipher       AES (GCM, CBC, ECB) and RSA (OAEP, PKCS#1)
- Signature    RSA and ECDSA signing/verification
- KeyGenerator AES/HMAC keys, RSA key pairs
- Jwt          JWT sign/verify for HS, RS, ES families (RFC 7519)
- Otp          HOTP (RFC 4226) + TOTP (RFC 6238), authenticator-compatible
- Base32 / Base64Url, CryptoException

UI: com.codename1.components.OtpField -- segmented OTP input with
auto-advance, backspace stepping, paste distribution, and a complete
listener.

Impl layer:
- CodenameOneImplementation gains aesEncrypt/Decrypt, rsaEncrypt/Decrypt,
  cryptoSign/Verify, secureRandomBytes, generateRsaKeyPair,
  generateSymmetricKey. Default implementation uses java.security via
  reflection so JavaSE simulator and Android work out of the box.
- com.codename1.io.Util exposes narrow public delegates the security
  package uses; getImplementation() stays package-private.

iOS port:
- New Ports/iOSPort/nativeSources/CN1Crypto.{h,m} backs AES-CBC/GCM, RSA
  OAEP/PKCS#1, RSA/ECDSA sign+verify, RSA keypair generation, and secure
  random against Apple's Security framework + CommonCrypto.
- IOSNative + IOSImplementation override every crypto bridge method to
  route through CN1Crypto.

Tests: 32 new tests under maven/core-unittests with RFC reference vectors
(FIPS 180-4 for hashes, RFC 4231 for HMAC, RFC 4226/6238 for OTP), plus
AES-GCM tamper detection, RSA OAEP round-trip, RSA sign/verify with
tampering, and a JWT RS256 round-trip.

Developer guide: new "Cryptographic primitives" section in
docs/developer-guide/security.asciidoc with examples for every entry
point, an algorithm-constant reference table, and recommended-key-size
guidance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apps that don't reference com.codename1.security.* now have none of the
CommonCrypto / Security framework encryption symbols in their iOS binary
-- and in particular, the AES-GCM SPI symbols (CCCryptorGCMAddIV etc.)
stay completely out unless the app opts in.

CN1Crypto.h: declare placeholder #define toggles
  CN1_INCLUDE_CRYPTO
  CN1_INCLUDE_CRYPTO_GCM
(commented-out by default; flipped by IPhoneBuilder when relevant)

CN1Crypto.m / IOSNative.m crypto block:
  - All implementations wrapped in #ifdef CN1_INCLUDE_CRYPTO. When the
    define is absent we emit no-op stubs that always return
    CN1_CRYPTO_E_UNSUPPORTED so the IOSImplementation overrides have
    something to link against but no encryption symbols are referenced.
  - The AES-GCM SPI externs and cn1_crypto_aes_gcm body are nested
    inside a separate #ifdef CN1_INCLUDE_CRYPTO_GCM so even apps using
    AES-CBC / RSA / signatures don't pull in the private GCM symbols
    unless they ask for it.

IPhoneBuilder:
  - Adds usesCryptoAPI / usesCryptoGcm flags. usesCryptoAPI is set by
    scanClassesForPermissions when any class in com/codename1/security/
    is referenced; usesCryptoGcm is opt-in via the ios.crypto.gcm
    build hint (default false).
  - Flips the CN1Crypto.h placeholders to the active defines when
    needed.
  - When the crypto API is used, injects
    <key>ITSAppUsesNonExemptEncryption</key><false/> into Info.plist so
    App Store Connect doesn't re-prompt on every upload. We always
    route through Apple-provided crypto (and, for GCM opt-in, stable
    SPI symbols backed by libcommonCrypto), which qualifies for the
    EAR 740.17 standard-cryptography exemption.
  - ios.appUsesNonExemptEncryption build hint overrides the default
    -- pass "true" if the app links proprietary crypto on top of ours,
    or "" to omit the key and answer in App Store Connect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves conflicts with the parallel "com.codename1.security: biometric
auth + secure storage" addition (#4987) that also landed in com.codename1.security.
The two contributions are independent class sets that happen to share the
package -- preserved both.

Conflict resolution:

- IOSNative.m: keep both the crypto bridge block (#ifdef CN1_INCLUDE_CRYPTO)
  and the biometrics + SecureStorage block back-to-back.
- IPhoneBuilder.java: keep usesBiometrics + usesCryptoAPI/usesCryptoGcm
  fields side by side and route classes in com/codename1/security/ to the
  right flag by name (Biometric*, SecureStorage and AuthenticationOptions
  go to biometrics; everything else goes to crypto).
- GenerateCN1AccessRegistry.java: extend the existing one-release
  INTERNAL_CN1_TYPES exclusion to cover the new crypto types too, so the
  playground bridge generator skips them until the cloud TeaVM backend
  catches up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Image references: No unused images detected (report)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 21, 2026

Compared 20 screenshots: 20 matched.
✅ JavaScript-port screenshot tests passed.

@github-actions
Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 21, 2026

Compared 110 screenshots: 110 matched.

Native Android coverage

  • 📊 Line coverage: 12.01% (6773/56385 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 9.73% (34039/349948), branch 4.20% (1393/33188), complexity 5.25% (1669/31808), method 9.14% (1358/14862), class 14.99% (303/2021)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 12.01% (6773/56385 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 9.73% (34039/349948), branch 4.20% (1393/33188), complexity 5.25% (1669/31808), method 9.14% (1358/14862), class 14.99% (303/2021)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 858.000 ms
Base64 CN1 encode 148.000 ms
Base64 encode ratio (CN1/native) 0.172x (82.8% faster)
Base64 native decode 804.000 ms
Base64 CN1 decode 175.000 ms
Base64 decode ratio (CN1/native) 0.218x (78.2% faster)
Image encode benchmark status skipped (SIMD unsupported)

The previous default implementation used java.security via reflection
inside CodenameOneImplementation. The core compiles against the CLDC11
java.lang.Class stub (no getMethod / getConstructor) and the iOS port
goes through ParparVM (no java.lang.reflect.Method symbols), so the
reflection broke the Ant test-javase build, the iOS native compile,
and every transitively-failing job (build, build-ios, build-ios-metal,
native-ios, packaging, build-test 8/17/21).

Refactor:
- CodenameOneImplementation: crypto methods now throw a clear
  "not supported on this platform" RuntimeException by default;
  zero java.security / javax.crypto references in core.
- JavaSEPort: real implementations using direct java.security /
  javax.crypto calls (full JDK is on the classpath at compile time
  and at runtime in the simulator).
- AndroidImplementation: same direct-JCE overrides; Android ships
  the standard JCE provider.
- TestCodenameOneImplementation (unit-test fixture in core-unittests):
  same overrides so the existing 32 crypto tests still exercise the
  bridge end-to-end.
- iOS port already overrides via IOSNative + CN1Crypto.{h,m}; no
  change there.

Also fixes vale-linter alerts on the new developer guide section:
- "and so on" -> rewritten without the suggestion
- "it is" -> "it's"
- "very deliberately" -> "have decided"
- "auto-advancing" -> "advances to the next box"

32/32 tests pass on the JavaSE bridge (Hash, Hmac, OtpField, Jwt,
Cipher, Signature, KeyGenerator, SecureRandom round-trips).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 21, 2026

Compared 11 screenshots: 11 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

shai-almog and others added 2 commits May 21, 2026 18:32
CI's static-analysis quality gate fails the build on a set of forbidden
PMD rules. Bring the new package into compliance:

- ControlStatementBraces: add { ... } around single-statement if / else
  / for / while bodies that the previous draft wrote inline.
- MissingOverride: annotate every method that overrides one of
  MessageDigestImpl's abstract / virtual hooks (reset, digest,
  digestLength, update, processBlock, writeStateBigEndian) and the
  Block64 base-class update overrides. Also annotate the
  DataChangedListener.dataChanged inner class in OtpField.
- LiteralsFirstInComparisons: flip s.equals("X") -> "X".equals(s) in
  MessageDigestImpl.create and Hmac.blockSizeFor.
- EmptyControlStatement: drop the empty if-truncated branch in
  Sha512Family.digest; collapse to a single !truncated check.
- ForLoopCanBeForeach: convert the array index-loops to enhanced for
  in Hash.toHex, Base32.encode and OtpField.fireCompleteIfFull.
- OneDeclarationPerLine: split chained int/long h0,h1,h2,...
  declarations in the SHA inner classes onto separate lines.
- ClassNamingConventions: rename inner classes Sha2_32 -> Sha256Family
  and Sha2_64 -> Sha512Family (the underscore violated the rule).

Local pmd:check on the new files now reports 0 violations from this PR.

Also pulls in the vale-asciidoc fixes for security.asciidoc that the
previous commit dropped (and that the build-docs job had already
flagged before this).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A second CI gate -- Checkstyle, also bound to the verify phase of
core-unittests -- flagged 109 brace-placement, whitespace, and
continuation-indent issues across the new files. Bring them to zero:

- LeftCurlyCheck (94 instances): split single-line `if (x) { y; }` and
  single-line method definitions like
  `public byte[] md5(byte[] d) { return create(MD5).digest(d); }`
  into the canonical three-line form. Codenames One's checkstyle
  config requires a newline immediately after the opening brace.
- WhitespaceAfterCheck (15 instances): add spaces after commas in
  Hash.HEX array literal and after primitive `(long)` casts in
  SecureRandom.longBelow.
- IndentationCheck (16 instances): bump SHA-512 word-mixing
  continuation lines from 23 to 24 columns to match the
  expected level (the `^` operator was one column shy of the
  canonical four-space continuation).

Local mvn checkstyle:check + pmd:check both report 0 violations from
this PR after these changes; 32/32 security tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 21, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 299 seconds

Build and Run Timing

Metric Duration
Simulator Boot 89000 ms
Simulator Boot (Run) 3000 ms
App Install 19000 ms
App Launch 53000 ms
Test Execution 345000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1370.000 ms
Base64 CN1 encode 2066.000 ms
Base64 encode ratio (CN1/native) 1.508x (50.8% slower)
Base64 native decode 569.000 ms
Base64 CN1 decode 2076.000 ms
Base64 decode ratio (CN1/native) 3.649x (264.9% slower)
Base64 SIMD encode 744.000 ms
Base64 encode ratio (SIMD/native) 0.543x (45.7% faster)
Base64 encode ratio (SIMD/CN1) 0.360x (64.0% faster)
Base64 SIMD decode 807.000 ms
Base64 decode ratio (SIMD/native) 1.418x (41.8% slower)
Base64 decode ratio (SIMD/CN1) 0.389x (61.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 165.000 ms
Image createMask (SIMD on) 27.000 ms
Image createMask ratio (SIMD on/off) 0.164x (83.6% faster)
Image applyMask (SIMD off) 353.000 ms
Image applyMask (SIMD on) 195.000 ms
Image applyMask ratio (SIMD on/off) 0.552x (44.8% faster)
Image modifyAlpha (SIMD off) 296.000 ms
Image modifyAlpha (SIMD on) 144.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.486x (51.4% faster)
Image modifyAlpha removeColor (SIMD off) 728.000 ms
Image modifyAlpha removeColor (SIMD on) 148.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.203x (79.7% faster)
Image PNG encode (SIMD off) 2042.000 ms
Image PNG encode (SIMD on) 1508.000 ms
Image PNG encode ratio (SIMD on/off) 0.738x (26.2% faster)
Image JPEG encode 1020.000 ms

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 21, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 249 seconds

Build and Run Timing

Metric Duration
Simulator Boot 88000 ms
Simulator Boot (Run) 2000 ms
App Install 21000 ms
App Launch 5000 ms
Test Execution 344000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 980.000 ms
Base64 CN1 encode 2063.000 ms
Base64 encode ratio (CN1/native) 2.105x (110.5% slower)
Base64 native decode 404.000 ms
Base64 CN1 decode 1411.000 ms
Base64 decode ratio (CN1/native) 3.493x (249.3% slower)
Base64 SIMD encode 569.000 ms
Base64 encode ratio (SIMD/native) 0.581x (41.9% faster)
Base64 encode ratio (SIMD/CN1) 0.276x (72.4% faster)
Base64 SIMD decode 452.000 ms
Base64 decode ratio (SIMD/native) 1.119x (11.9% slower)
Base64 decode ratio (SIMD/CN1) 0.320x (68.0% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 81.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.123x (87.7% faster)
Image applyMask (SIMD off) 142.000 ms
Image applyMask (SIMD on) 104.000 ms
Image applyMask ratio (SIMD on/off) 0.732x (26.8% faster)
Image modifyAlpha (SIMD off) 334.000 ms
Image modifyAlpha (SIMD on) 2147.000 ms
Image modifyAlpha ratio (SIMD on/off) 6.428x (542.8% slower)
Image modifyAlpha removeColor (SIMD off) 328.000 ms
Image modifyAlpha removeColor (SIMD on) 242.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.738x (26.2% faster)
Image PNG encode (SIMD off) 1911.000 ms
Image PNG encode (SIMD on) 1084.000 ms
Image PNG encode ratio (SIMD on/off) 0.567x (43.3% faster)
Image JPEG encode 576.000 ms

shai-almog and others added 3 commits May 21, 2026 20:56
… device test

Code-review feedback on PR #4994:

1. Reuse the existing util.Base64 instead of adding a parallel Base64Url
   class. util.Base64 is already SIMD-optimized; layer URL-safe encode/decode
   on top of its encodeNoNewline path and inherit the speedup.
   - util.Base64: new encodeUrlSafe(byte[]) / decodeUrlSafe(String) that
     run through the same fast encoder, then map +-> / -> _ and strip
     trailing = padding (RFC 4648 sec5).
   - Jwt, JwtTest, OtpTest, package-info: switch to the new helpers.
   - Drop security/Base64Url.java entirely.

2. Pull the common key fields (algorithm, encoded, format) into a new
   abstract Key base class. PublicKey/PrivateKey/SecretKey now extend it
   and only carry the type-specific extras (static factories for the
   asymmetric pair; getBitLength on the symmetric one).

3. Otp.otpauthUri(issuer, accountName, secret, ...): builds the canonical
   otpauth://totp/... URI per the Google Authenticator KeyUri spec so the
   secret can be displayed as a QR code on enrolment screens. Six-digit /
   30-second / SHA-1 default matches what every authenticator app expects.

4. Developer guide: expand the OTP section into a real two-factor-auth
   tutorial -- enrolment via otpauthUri + QR rendering, verification via
   OtpField + Otp.verifyTotp, server-side guidance, rate-limiting note.
   Documents three approaches for actually rendering the QR (server-side
   render URL, QR cn1lib, plain Base32 typed entry) since core doesn't
   ship a QR encoder yet.

5. CryptoApiTest: device-side coverage in scripts/hellocodenameone that
   mirrors the JUnit assertions (hash + HMAC RFC vectors, HOTP/TOTP RFC
   vectors, AES-GCM round-trip + tamper detection, RSA-OAEP round-trip,
   RSA-SHA-256 sign/verify, JWT HS256 + RS256 round-trips, otpauthUri
   shape). Registered in Cn1ssDeviceRunner; skipped on HTML5 (no crypto
   bridge on the JS port yet).

SIMD acceleration for hashing was investigated but declined: SHA-2's
round state machine has data dependencies that block single-message
vectorization, and the current Simd surface doesn't expose 32/64-bit
rotation. The natural SIMD beneficiary in this PR -- Base64 -- is
already covered by util.Base64.

Local: pmd:check, checkstyle:check both 0 violations; 34 JUnit tests
pass (32 from prior commits + 2 new otpauthUri tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's javac on JDK 8 / 17 / 21 uses the US-ASCII default file.encoding
(file.encoding=UTF-8 is only the JDK 18+ default per JEP 400) and
choked on the section-sign character in two new doc comments:

  RFC 4648 §5

Swap the symbol for the spelled-out "sec" abbreviation, mirroring the
ASCII-only convention noted in the previous biometrics commit
(#4987) that fixed the same family of failures for the em-dash.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The crypto bridge methods on IOSNative -- aesCbc, aesGcm, rsaEncrypt,
rsaDecrypt, sign, verify, generateRsaKeyPair -- all return an int.
ParparVM emits two C entry points for every non-void native: the
unmangled implementation (com_..._methodName___paramTypes) and a
_R_<returnType>-suffixed forwarder that the bytecode dispatcher
actually calls.

The earlier commits provided only the first half, so the previous
build-ios job (which transpiled the framework but didn't transitively
include the crypto code path) passed -- the symbols were dead-code-
eliminated. Adding CryptoApiTest to scripts/hellocodenameone now keeps
those methods alive, the linker hunts for the _R_int wrappers, and
the iOS packaging job fails with:

    Undefined symbols for architecture arm64:
      "_com_codename1_impl_ios_IOSNative_aesCbc___..._R_int"
      "_com_codename1_impl_ios_IOSNative_aesGcm___..._R_int"
      ...

Forward each wrapper to the matching base implementation. The base
itself is either the real CommonCrypto-backed version (when
CN1_INCLUDE_CRYPTO is defined by IPhoneBuilder) or the
CN1_CRYPTO_E_UNSUPPORTED stub, so this single set of wrappers serves
both build configurations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog merged commit d117996 into master May 21, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant