@@ -19,7 +19,6 @@ Real-world examples showing how to use JSEncrypt for common encryption scenarios
1919
20201 . TOC
2121{: toc }
22-
2322---
2423
2524## Basic Encryption/Decryption
@@ -89,6 +88,290 @@ fetch('/api/login', {
8988
9089---
9190
91+ ## SHA-256 Digital Signatures
92+
93+ ### Using the Convenience Methods
94+
95+ JSEncrypt provides convenient ` signSha256() ` and ` verifySha256() ` methods that automatically handle SHA-256 hashing for you.
96+
97+ ``` javascript
98+ import { JSEncrypt } from ' jsencrypt' ;
99+
100+ // Initialize with your key pair
101+ const crypt = new JSEncrypt ();
102+ crypt .setPrivateKey (privateKey);
103+ crypt .setPublicKey (publicKey);
104+
105+ // Simple message signing with SHA-256
106+ const message = " Important data to sign" ;
107+ const signature = crypt .signSha256 (message);
108+ console .log (' Signature:' , signature);
109+ const isValid = crypt .verifySha256 (message, signature);
110+ console .log (' Signature valid:' , isValid); // true
111+ ```
112+
113+ ### API Token Validation
114+
115+ ``` javascript
116+ class APITokenManager {
117+ constructor (privateKey , publicKey ) {
118+ this .crypt = new JSEncrypt ();
119+ this .privateKey = privateKey;
120+ this .publicKey = publicKey;
121+ }
122+
123+ // Generate a signed API token
124+ generateToken (userId , permissions , expiresIn = 3600 ) {
125+ const tokenData = {
126+ userId: userId,
127+ permissions: permissions,
128+ issuedAt: Math .floor (Date .now () / 1000 ),
129+ expiresAt: Math .floor (Date .now () / 1000 ) + expiresIn
130+ };
131+
132+ const payload = JSON .stringify (tokenData);
133+ this .crypt .setPrivateKey (this .privateKey );
134+ const signature = this .crypt .signSha256 (payload);
135+
136+ // Return token as base64 encoded payload + signature
137+ const token = Buffer .from (JSON .stringify ({
138+ payload: payload,
139+ signature: signature
140+ })).toString (' base64' );
141+
142+ return token;
143+ }
144+
145+ // Validate an API token
146+ validateToken (token ) {
147+ try {
148+ // Decode the token
149+ const decoded = JSON .parse (Buffer .from (token, ' base64' ).toString ());
150+ const { payload , signature } = decoded;
151+
152+ // Verify signature using convenience method
153+ this .crypt .setPublicKey (this .publicKey );
154+ const isValidSignature = this .crypt .verifySha256 (payload, signature);
155+
156+ if (! isValidSignature) {
157+ return { valid: false , reason: ' Invalid signature' };
158+ }
159+
160+ // Check expiration
161+ const tokenData = JSON .parse (payload);
162+ const now = Math .floor (Date .now () / 1000 );
163+
164+ if (tokenData .expiresAt < now) {
165+ return { valid: false , reason: ' Token expired' };
166+ }
167+
168+ return {
169+ valid: true ,
170+ data: tokenData
171+ };
172+ } catch (error) {
173+ return { valid: false , reason: ' Invalid token format' };
174+ }
175+ }
176+ }
177+
178+ // Usage
179+ const tokenManager = new APITokenManager (privateKey, publicKey);
180+
181+ // Generate a token for user
182+ const token = tokenManager .generateToken (12345 , [' read' , ' write' ], 7200 ); // 2 hours
183+ console .log (' Generated token:' , token);
184+
185+ // Later, validate the token
186+ const validation = tokenManager .validateToken (token);
187+ if (validation .valid ) {
188+ console .log (' Token valid for user:' , validation .data .userId );
189+ console .log (' Permissions:' , validation .data .permissions );
190+ } else {
191+ console .log (' Token invalid:' , validation .reason );
192+ }
193+ ```
194+
195+ ### Message Integrity Verification
196+
197+ ``` javascript
198+ class MessageIntegrityChecker {
199+ constructor (privateKey , publicKey ) {
200+ this .signer = new JSEncrypt ();
201+ this .verifier = new JSEncrypt ();
202+ this .signer .setPrivateKey (privateKey);
203+ this .verifier .setPublicKey (publicKey);
204+ }
205+
206+ // Create a signed message with metadata
207+ createSignedMessage (content , metadata = {}) {
208+ const messageData = {
209+ content: content,
210+ timestamp: Date .now (),
211+ metadata: metadata
212+ };
213+
214+ const messageString = JSON .stringify (messageData);
215+ const signature = this .signer .signSha256 (messageString);
216+
217+ return {
218+ message: messageData,
219+ signature: signature
220+ };
221+ }
222+
223+ // Verify a signed message
224+ verifyMessage (signedMessage ) {
225+ const { message , signature } = signedMessage;
226+ const messageString = JSON .stringify (message);
227+
228+ // Verify using SHA-256 convenience method
229+ const isValid = this .verifier .verifySha256 (messageString, signature);
230+
231+ if (! isValid) {
232+ return { valid: false , reason: ' Signature verification failed' };
233+ }
234+
235+ return {
236+ valid: true ,
237+ content: message .content ,
238+ timestamp: new Date (message .timestamp ),
239+ metadata: message .metadata
240+ };
241+ }
242+ }
243+
244+ // Usage Example
245+ const checker = new MessageIntegrityChecker (privateKey, publicKey);
246+
247+ // Create a signed message
248+ const signedMessage = checker .createSignedMessage (
249+ " This is a secure message" ,
250+ { sender: " Alice" , priority: " high" }
251+ );
252+
253+ console .log (' Signed message:' , signedMessage);
254+
255+ // Verify the message
256+ const verification = checker .verifyMessage (signedMessage);
257+ if (verification .valid ) {
258+ console .log (' Message verified:' , verification .content );
259+ console .log (' Sent by:' , verification .metadata .sender );
260+ } else {
261+ console .log (' Verification failed:' , verification .reason );
262+ }
263+ ```
264+
265+ ### Simple JWT Implementation
266+
267+ Here's a straightforward JWT implementation using the ` signSha256 ` and ` verifySha256 ` methods:
268+
269+ ``` javascript
270+ class SimpleJWT {
271+ constructor (privateKey , publicKey ) {
272+ this .signer = new JSEncrypt ();
273+ this .verifier = new JSEncrypt ();
274+ this .signer .setPrivateKey (privateKey);
275+ this .verifier .setPublicKey (publicKey);
276+ }
277+
278+ // Create a simple JWT
279+ createToken (payload , expiresInSeconds = 3600 ) {
280+ const header = {
281+ alg: ' RS256' ,
282+ typ: ' JWT'
283+ };
284+
285+ const claims = {
286+ ... payload,
287+ iat: Math .floor (Date .now () / 1000 ),
288+ exp: Math .floor (Date .now () / 1000 ) + expiresInSeconds
289+ };
290+
291+ // Encode header and payload
292+ const encodedHeader = this .base64UrlEncode (JSON .stringify (header));
293+ const encodedPayload = this .base64UrlEncode (JSON .stringify (claims));
294+
295+ // Create signing input
296+ const signingInput = ` ${ encodedHeader} .${ encodedPayload} ` ;
297+ const signature = this .signer .signSha256 (signingInput);
298+ const encodedSignature = this .base64UrlEncode (signature);
299+
300+ return ` ${ signingInput} .${ encodedSignature} ` ;
301+ }
302+
303+ // Verify and decode a JWT
304+ verifyToken (token ) {
305+ const parts = token .split (' .' );
306+ if (parts .length !== 3 ) {
307+ throw new Error (' Invalid JWT format' );
308+ }
309+
310+ const [encodedHeader , encodedPayload , encodedSignature ] = parts;
311+ const signingInput = ` ${ encodedHeader} .${ encodedPayload} ` ;
312+
313+ // Decode signature and verify using convenience method
314+ const signature = this .base64UrlDecode (encodedSignature);
315+ const isValid = this .verifier .verifySha256 (signingInput, signature);
316+
317+ if (! isValid) {
318+ throw new Error (' Invalid signature' );
319+ }
320+
321+ // Decode and check expiration
322+ const payload = JSON .parse (this .base64UrlDecode (encodedPayload));
323+ const now = Math .floor (Date .now () / 1000 );
324+
325+ if (payload .exp && payload .exp < now) {
326+ throw new Error (' Token expired' );
327+ }
328+
329+ return payload;
330+ }
331+
332+ // Base64 URL encoding/decoding utilities
333+ base64UrlEncode (str ) {
334+ return Buffer .from (str, ' utf8' )
335+ .toString (' base64' )
336+ .replace (/ \+ / g , ' -' )
337+ .replace (/ \/ / g , ' _' )
338+ .replace (/ =/ g , ' ' );
339+ }
340+
341+ base64UrlDecode (str ) {
342+ // Add padding
343+ str += ' =' .repeat ((4 - str .length % 4 ) % 4 );
344+ // Convert back from URL-safe base64
345+ const standardBase64 = str .replace (/ -/ g , ' +' ).replace (/ _/ g , ' /' );
346+ return Buffer .from (standardBase64, ' base64' ).toString (' utf8' );
347+ }
348+ }
349+
350+ // Usage Example
351+ const jwt = new SimpleJWT (privateKey, publicKey);
352+
353+ // Create a token
354+ const token = jwt .createToken ({
355+ userId: 12345 ,
356+ username: ' john.doe' ,
357+ role: ' admin'
358+ }, 7200 ); // 2 hours
359+
360+ console .log (' JWT Token:' , token);
361+
362+ // Verify the token
363+ try {
364+ const decoded = jwt .verifyToken (token);
365+ console .log (' Token valid! User:' , decoded .username );
366+ console .log (' Role:' , decoded .role );
367+ console .log (' Expires:' , new Date (decoded .exp * 1000 ));
368+ } catch (error) {
369+ console .error (' Token verification failed:' , error .message );
370+ }
371+ ```
372+
373+ ---
374+
92375## JWT Token Signing with RSA
93376
94377### Creating JWT Tokens with RSA Signatures
@@ -160,16 +443,14 @@ class RSAJWTManager {
160443
161444 signWithRSA (data ) {
162445 this .crypt .setPrivateKey (this .privateKey );
163- const hash = crypto .createHash (' sha256' ).update (data).digest ();
164- const signature = this .crypt .sign (hash .toString (' base64' ), ' sha256' , ' base64' );
446+ const signature = this .crypt .signSha256 (data);
165447 return this .base64UrlEncode (signature);
166448 }
167449
168450 verifyRSASignature (data , signature ) {
169451 this .crypt .setPublicKey (this .publicKey );
170- const hash = crypto .createHash (' sha256' ).update (data).digest ();
171452 const decodedSignature = this .base64UrlDecode (signature);
172- return this .crypt .verify ( hash . toString ( ' base64 ' ) , decodedSignature, ' sha256 ' );
453+ return this .crypt .verifySha256 (data , decodedSignature);
173454 }
174455
175456 base64UrlEncode (str ) {
@@ -355,7 +636,7 @@ class DocumentSigner {
355636
356637 // Sign the payload
357638 const payloadString = JSON .stringify (signaturePayload);
358- const signature = this .crypt .sign (payloadString, ' sha256 ' , ' base64 ' );
639+ const signature = this .crypt .signSha256 (payloadString);
359640
360641 return {
361642 document : documentContent,
@@ -382,7 +663,8 @@ class DocumentSigner {
382663
383664 // Verify signature
384665 const payloadString = JSON .stringify (signaturePayload);
385- const isValidSignature = this .crypt .verify (payloadString, signature, ' sha256' );
666+ // Use the new verifySha256 convenience method
667+ const isValidSignature = this .crypt .verifySha256 (payloadString, signature);
386668
387669 if (! isValidSignature) {
388670 return { valid: false , reason: ' Invalid signature' };
0 commit comments