66using System . Text ;
77using System . Text . Json ;
88using OpenClaw . Shared . Mcp ;
9- using NSec . Cryptography ;
9+ using Org . BouncyCastle . Math . EC . Rfc8032 ;
1010
1111namespace OpenClaw . Shared ;
1212
@@ -17,18 +17,16 @@ public class DeviceIdentity
1717{
1818 private readonly string _keyPath ;
1919 private readonly IOpenClawLogger _logger ;
20- private Key ? _privateKey ;
21- private PublicKey ? _publicKey ;
20+ private byte [ ] ? _privateKey ;
21+ private byte [ ] ? _publicKey ;
2222 private string ? _deviceId ;
2323 private string ? _deviceToken ;
2424 private string [ ] ? _deviceTokenScopes ;
2525 private string ? _nodeDeviceToken ;
2626 private string [ ] ? _nodeDeviceTokenScopes ;
2727
28- private static readonly SignatureAlgorithm Ed25519Algorithm = SignatureAlgorithm . Ed25519 ;
29-
3028 public string DeviceId => _deviceId ?? throw new InvalidOperationException ( "Device not initialized" ) ;
31- public string PublicKeyBase64Url => _publicKey != null ? Base64UrlEncode ( _publicKey . Export ( KeyBlobFormat . RawPublicKey ) ) : throw new InvalidOperationException ( "Device not initialized" ) ;
29+ public string PublicKeyBase64Url => _publicKey != null ? Base64UrlEncode ( _publicKey ) : throw new InvalidOperationException ( "Device not initialized" ) ;
3230 public string ? DeviceToken => _deviceToken ;
3331 public IReadOnlyList < string > ? DeviceTokenScopes => _deviceTokenScopes ;
3432 public string ? NodeDeviceToken => _nodeDeviceToken ;
@@ -192,9 +190,9 @@ private void LoadExisting()
192190 return ;
193191 }
194192
195- var privateKeyBytes = Convert . FromBase64String ( data . PrivateKeyBase64 ) ;
196- _privateKey = Key . Import ( Ed25519Algorithm , privateKeyBytes , KeyBlobFormat . RawPrivateKey ) ;
197- _publicKey = _privateKey . PublicKey ;
193+ _privateKey = Convert . FromBase64String ( data . PrivateKeyBase64 ) ;
194+ _publicKey = new byte [ Ed25519 . PublicKeySize ] ;
195+ Ed25519 . GeneratePublicKey ( _privateKey , 0 , _publicKey , 0 ) ;
198196 _deviceId = data . DeviceId ;
199197 _deviceToken = data . DeviceToken ;
200198 _deviceTokenScopes = NormalizeScopes ( data . DeviceTokenScopes ) ;
@@ -214,20 +212,21 @@ private void GenerateNew()
214212 {
215213 _logger . Info ( "Generating new Ed25519 device keypair..." ) ;
216214
217- // Generate Ed25519 keypair using NSec
218- _privateKey = Key . Create ( Ed25519Algorithm , new KeyCreationParameters { ExportPolicy = KeyExportPolicies . AllowPlaintextExport } ) ;
219- _publicKey = _privateKey . PublicKey ;
215+ _privateKey = new byte [ Ed25519 . SecretKeySize ] ;
216+ RandomNumberGenerator . Fill ( _privateKey ) ;
217+ _publicKey = new byte [ Ed25519 . PublicKeySize ] ;
218+ Ed25519 . GeneratePublicKey ( _privateKey , 0 , _publicKey , 0 ) ;
220219
221220 // Get raw 32-byte public key
222- var publicKeyBytes = _publicKey . Export ( KeyBlobFormat . RawPublicKey ) ;
221+ var publicKeyBytes = _publicKey ;
223222
224223 // Device ID is SHA256 hash of raw 32-byte public key (hex encoded)
225224 using var sha256 = SHA256 . Create ( ) ;
226225 var hashBytes = sha256 . ComputeHash ( publicKeyBytes ) ;
227226 _deviceId = Convert . ToHexString ( hashBytes ) . ToLowerInvariant ( ) ;
228227
229228 // Export private key for storage
230- var privateKeyBytes = _privateKey . Export ( KeyBlobFormat . RawPrivateKey ) ;
229+ var privateKeyBytes = _privateKey ;
231230
232231 // Save to disk
233232 var data = new DeviceKeyData
@@ -268,7 +267,7 @@ public string SignPayload(string nonce, long signedAtMs, string clientId, string
268267
269268 // Sign with Ed25519
270269 var dataBytes = Encoding . UTF8 . GetBytes ( payload ) ;
271- var signature = Ed25519Algorithm . Sign ( _privateKey , dataBytes ) ;
270+ var signature = SignEd25519 ( dataBytes ) ;
272271
273272 // Return base64url encoded signature
274273 return Base64UrlEncode ( signature ) ;
@@ -304,7 +303,7 @@ public string SignConnectPayloadV3(
304303 deviceFamily ) ;
305304
306305 var dataBytes = Encoding . UTF8 . GetBytes ( payload ) ;
307- var signature = Ed25519Algorithm . Sign ( _privateKey , dataBytes ) ;
306+ var signature = SignEd25519 ( dataBytes ) ;
308307 return Base64UrlEncode ( signature ) ;
309308 }
310309
@@ -376,7 +375,7 @@ public string SignConnectPayloadV2(
376375 authToken ) ;
377376
378377 var dataBytes = Encoding . UTF8 . GetBytes ( payload ) ;
379- var signature = Ed25519Algorithm . Sign ( _privateKey , dataBytes ) ;
378+ var signature = SignEd25519 ( dataBytes ) ;
380379 return Base64UrlEncode ( signature ) ;
381380 }
382381
@@ -563,6 +562,16 @@ private static string DescribeException(Exception ex)
563562 ? message
564563 : $ "{ message } (inner { ex . InnerException . GetType ( ) . Name } : { ex . InnerException . Message } )";
565564 }
565+
566+ private byte [ ] SignEd25519 ( byte [ ] data )
567+ {
568+ if ( _privateKey == null )
569+ throw new InvalidOperationException ( "Device not initialized" ) ;
570+
571+ var signature = new byte [ Ed25519 . SignatureSize ] ;
572+ Ed25519 . Sign ( _privateKey , 0 , data , 0 , data . Length , signature , 0 ) ;
573+ return signature ;
574+ }
566575
567576 private static string Base64UrlEncode ( byte [ ] data )
568577 {
0 commit comments