Chiffrement et émission d'AiToken
Chiffrement et émission d'AiToken
Vue d'ensemble
AiToken est le justificatif central de l'intégration à l'espace de travail : il encapsule l'ID de l'organisation et l'e-mail du compte de l'employé, chiffré à l'aide d'une clé publique RSA puis concaténé pour former une URL de connexion dédiée, permettant aux employés d'entreprise d'ouvrir l'espace de travail sans connexion dans l'APP mobile.
Obtenir la clé publique
- Ouvrez la version Web → Gestion de l'espace → Paramètres avancés → Marque → Intégration
- Dans la zone d'intégration, repérez la clé publique, cliquez pour l'afficher ou la copier
- Si vous devez régénérer la clé (rare, cela invalide tous les Tokens déjà émis), cliquez sur
Réinitialiser
Chiffrer un AiToken en tant qu'employé d'entreprise
Aperçu du processus
Étape 1 : e-mail du membre ─── Chiffrement RSA (clé publique) ───► octets emailEncrypted
Étape 2 : emailEncrypted ─── Encodage Base64 ───► emailRSAStr
Étape 3 : concaténation de la chaîne {projectId}:{emailRSAStr}
Étape 4 : chaîne concaténée ─── Encodage Base64 ───► AiToken final
Étape 1 : e-mail du membre ─── Chiffrement RSA (clé publique) ───► octets emailEncrypted
Étape 2 : emailEncrypted ─── Encodage Base64 ───► emailRSAStr
Étape 3 : concaténation de la chaîne {projectId}:{emailRSAStr}
Étape 4 : chaîne concaténée ─── Encodage Base64 ───► AiToken final
Ce bloc de code dans la fenêtre flottante
Paramètres de l'algorithme
| Paramètre | Valeur |
|---|---|
| Algorithme RSA | RSA/ECB/PKCS1Padding (soit RSAES-PKCS1-V1_5) |
| Format de la clé publique | X.509 (SubjectPublicKeyInfo), encodée en Base64 |
| Encodage de sortie | Deux passages en Base64 |
Exemple de code de chiffrement en Java
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Main {
private static final String RSA_ALGORITHM = "RSA";
private static final String RSA_TRANSFORMATION = "RSA/ECB/PKCS1Padding";
/**
* Encrypts data using RSA public key.
*
* @param data The data to encrypt.
* @param publicKeyStr The Base64 encoded RSA public key.
* @return Encrypted data bytes.
*/
public static byte[] encrypt(byte[] data, String publicKeyStr) throws Exception {
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* Generates a login key by encrypting the email and combining with projectId.
*
* @param projectId The project ID.
* @param email The user's email.
* @param publicKey The Base64 encoded RSA public key.
* @return The final login key string.
* @throws Exception if encryption fails.
*/
public static String generateLoginKey(String projectId, String email, String publicKey) throws Exception {
byte[] emailEncrypted = encrypt(email.getBytes(StandardCharsets.UTF_8), publicKey);
String emailRSAStr = Base64.getEncoder().encodeToString(emailEncrypted);
String keyStr = projectId + ":" + emailRSAStr;
return Base64.getEncoder().encodeToString(keyStr.getBytes(StandardCharsets.UTF_8));
}
public static void main(String[] args) {
String projectId = "your project ID";
String email = "your email";
String publicKey = "your public key";
try {
String key = generateLoginKey(projectId, email, publicKey);
System.out.println(key);
} catch (Exception e) {
System.err.println("Failed to generate login key: " + e.getMessage());
}
}
}
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Main {
private static final String RSA_ALGORITHM = "RSA";
private static final String RSA_TRANSFORMATION = "RSA/ECB/PKCS1Padding";
/**
* Encrypts data using RSA public key.
*
* @param data The data to encrypt.
* @param publicKeyStr The Base64 encoded RSA public key.
* @return Encrypted data bytes.
*/
public static byte[] encrypt(byte[] data, String publicKeyStr) throws Exception {
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* Generates a login key by encrypting the email and combining with projectId.
*
* @param projectId The project ID.
* @param email The user's email.
* @param publicKey The Base64 encoded RSA public key.
* @return The final login key string.
* @throws Exception if encryption fails.
*/
public static String generateLoginKey(String projectId, String email, String publicKey) throws Exception {
byte[] emailEncrypted = encrypt(email.getBytes(StandardCharsets.UTF_8), publicKey);
String emailRSAStr = Base64.getEncoder().encodeToString(emailEncrypted);
String keyStr = projectId + ":" + emailRSAStr;
return Base64.getEncoder().encodeToString(keyStr.getBytes(StandardCharsets.UTF_8));
}
public static void main(String[] args) {
String projectId = "your project ID";
String email = "your email";
String publicKey = "your public key";
try {
String key = generateLoginKey(projectId, email, publicKey);
System.out.println(key);
} catch (Exception e) {
System.err.println("Failed to generate login key: " + e.getMessage());
}
}
}
Ce bloc de code dans la fenêtre flottante
Exemple de code de chiffrement en TypeScript
import * as forge from 'node-forge';
/**
* Encrypt data using RSA public key
* @param data Data to be encrypted
* @param publicKeyStr Base64 encoded public key string
* @returns Encrypted byte array
*/
export function encrypt(data: string, publicKeyStr: string): Uint8Array {
try {
// Decode Base64 public key
const publicKeyBytes = forge.util.decode64(publicKeyStr);
// Create public key object
const publicKey = forge.pki.publicKeyFromAsn1(forge.asn1.fromDer(publicKeyBytes));
// Use RSA encryption with PKCS1 padding (consistent with Java's default behavior)
const encrypted = publicKey.encrypt(data, 'RSAES-PKCS1-V1_5');
// Convert forge's byte string to Uint8Array
const bytes = new Uint8Array(encrypted.length);
for (let i = 0; i < encrypted.length; i++) {
bytes[i] = encrypted.charCodeAt(i) & 0xff;
}
return bytes;
} catch (error) {
throw new Error(`RSA encryption failed: ${error}`);
}
}
/**
* Convert byte array to Base64 string
* @param bytes Byte array
* @returns Base64 encoded string
*/
export function bytesToBase64(bytes: Uint8Array): string {
// Convert Uint8Array to string, then use forge's encode64
const binaryString = Array.from(bytes, byte => String.fromCharCode(byte)).join('');
return forge.util.encode64(binaryString);
}
/**
* Convert string to Base64
* @param str String to be encoded
* @returns Base64 encoded string
*/
export function stringToBase64(str: string): string {
return forge.util.encode64(str);
}
/**
* Main function - Generate encrypted key string
* @param projectId Project ID
* @param email Email address
* @param publicKey Base64 encoded RSA public key
* @returns Final encrypted Base64 string
*/
export function generateEncryptedKey(projectId: string, email: string, publicKey: string): string {
// Use RSA to encrypt email
const emailRSAEncrypt = encrypt(email, publicKey);
// Convert encryption result to Base64
const emailRSAStr = bytesToBase64(emailRSAEncrypt);
// Combine projectId and encrypted email
const keyStr = `${projectId}:${emailRSAStr}`;
// Encode the entire string with Base64
const result = stringToBase64(keyStr);
return result;
}
// Generate AiToken example
// generateEncryptedKey(projectId, email, publicKey)
import * as forge from 'node-forge';
/**
* Encrypt data using RSA public key
* @param data Data to be encrypted
* @param publicKeyStr Base64 encoded public key string
* @returns Encrypted byte array
*/
export function encrypt(data: string, publicKeyStr: string): Uint8Array {
try {
// Decode Base64 public key
const publicKeyBytes = forge.util.decode64(publicKeyStr);
// Create public key object
const publicKey = forge.pki.publicKeyFromAsn1(forge.asn1.fromDer(publicKeyBytes));
// Use RSA encryption with PKCS1 padding (consistent with Java's default behavior)
const encrypted = publicKey.encrypt(data, 'RSAES-PKCS1-V1_5');
// Convert forge's byte string to Uint8Array
const bytes = new Uint8Array(encrypted.length);
for (let i = 0; i < encrypted.length; i++) {
bytes[i] = encrypted.charCodeAt(i) & 0xff;
}
return bytes;
} catch (error) {
throw new Error(`RSA encryption failed: ${error}`);
}
}
/**
* Convert byte array to Base64 string
* @param bytes Byte array
* @returns Base64 encoded string
*/
export function bytesToBase64(bytes: Uint8Array): string {
// Convert Uint8Array to string, then use forge's encode64
const binaryString = Array.from(bytes, byte => String.fromCharCode(byte)).join('');
return forge.util.encode64(binaryString);
}
/**
* Convert string to Base64
* @param str String to be encoded
* @returns Base64 encoded string
*/
export function stringToBase64(str: string): string {
return forge.util.encode64(str);
}
/**
* Main function - Generate encrypted key string
* @param projectId Project ID
* @param email Email address
* @param publicKey Base64 encoded RSA public key
* @returns Final encrypted Base64 string
*/
export function generateEncryptedKey(projectId: string, email: string, publicKey: string): string {
// Use RSA to encrypt email
const emailRSAEncrypt = encrypt(email, publicKey);
// Convert encryption result to Base64
const emailRSAStr = bytesToBase64(emailRSAEncrypt);
// Combine projectId and encrypted email
const keyStr = `${projectId}:${emailRSAStr}`;
// Encode the entire string with Base64
const result = stringToBase64(keyStr);
return result;
}
// Generate AiToken example
// generateEncryptedKey(projectId, email, publicKey)
Ce bloc de code dans la fenêtre flottante
Générer l'URL de connexion dédiée
Générez l'URL de connexion dédiée du compte de l'employé selon le format {URL d'intégration de l'espace de travail}?{AiToken} :
https://gptbots.ai/space/h5/home?AiToken={AiToken chiffré}&hideClose=true
https://gptbots.ai/space/h5/home?AiToken={AiToken chiffré}&hideClose=true
Ce bloc de code dans la fenêtre flottante
Lorsqu'un employé d'entreprise ouvre, dans l'APP mobile, l'URL de connexion chiffrée dédiée à l'e-mail de son compte, il peut ouvrir l'espace de travail correspondant sans connexion.
Consignes de sécurité
| Point d'attention | Description |
|---|---|
| Sécurité de la clé publique | La clé publique peut être distribuée publiquement, mais le processus d'émission doit être effectué côté serveur, afin d'éviter que le client détienne directement l'ID du projet |
| Durée de validité du Token | L'AiToken n'a pas de notion de durée de validité ; il est recommandé de l'émettre côté backend au moment de la demande et de ne pas le mettre en cache durablement côté APP |
| Correspondance de l'e-mail | L'e-mail contenu dans l'AiToken doit être celui d'un membre déjà existant dans l'espace de travail, sinon l'utilisateur sera signalé comme inexistant |
| Liaison à l'organisation | Un même ID de projet (projectId) correspond à une organisation ; le membre doit appartenir à cette organisation |
| HTTPS | L'URL d'intégration doit être accessible via HTTPS afin d'éviter toute fuite du Token pendant le transport |
