PBToolboxAI v3 ← Site

crypto — n_pbt_crypto #

← Referencia de componentes · Índice de la guía

Hashes, HMAC, cifrado por contraseña, valores aleatorios y firmas RSA — la Web Crypto API del motor WebView2, que su PowerBuilder 10 no tiene en ningún otro sitio. Sin DLL de terceros, sin servicio: lo que el equipo ya sabe hacer, ofrecido a PowerScript.

▶ Verlo en vivo — Aplicación de demostración, mosaico Crypto: los resultados, el código que los produce y esta página, lado a lado.


En resumen #

Objeto no visualn_pbt_crypto
Sirve paraComprobar que un archivo no ha cambiado, guardar un secreto en un INI, firmar un pedido, autenticar una llamada a una API
PrincipioUna página oculta hace el cálculo; cada método es una llamada PowerScript normal que devuelve su valor
DependenciaEl runtime WebView2, que la biblioteca ya requiere — nada más

Inicio rápido #

n_pbt_crypto lnv_crypto
string ls_hash, ls_cipher

lnv_crypto = create n_pbt_crypto

// The fingerprint of a text, in hexadecimal
ls_hash = lnv_crypto.of_sha256("Invoice 4152, 690.00 EUR")

// A secret kept with a password : one string to store, the password to keep
ls_cipher = lnv_crypto.of_encrypt("s3cret", "The safe code is 4152.")
MessageBox("Back", lnv_crypto.of_decrypt("s3cret", ls_cipher))

destroy lnv_crypto

Cada método es una llamada que devuelve su valor: sin evento, sin espera que escribir.


Los formatos, legibles por otras herramientas #


Propiedades #

PropiedadTipoPredeterminadoFunción
is_last_errorstring""Por qué la última llamada devolvió una cadena vacía, false o un código negativo: contraseña errónea, archivo ilegible, algoritmo desconocido, límite demo
il_timeout_mslong20000Duración máxima de una llamada. Calcular el hash de un archivo grande o generar una clave de 4096 bits puede tardar unos segundos
il_pbkdf2_roundslong100000Rondas PBKDF2 de of_encrypt, of_password_hash y of_encrypt_file: unos 100 ms. Más es más lento para todos, atacante incluido

Constantes: HASH_MD5, HASH_SHA1, HASH_SHA256, HASH_SHA384, HASH_SHA512 para el algoritmo; KEY_2048, KEY_3072, KEY_4096 para el tamaño de una clave RSA, KEY_RSA_2048, KEY_EC_P256, KEY_ED25519 para el tipo de par; JWT_HS256, JWT_RS256, JWT_ES256, JWT_EDDSA; CHARSET_ALL, CHARSET_ALPHANUM, CHARSET_LETTERS, CHARSET_DIGITS, CHARSET_HEX.


Métodos #

MétodoFunción
of_open ( ) → longCrea la página oculta. Opcional — cada método lo hace — pero llamarlo al abrir la ventana paga el coste una vez. Devuelve el handle (> 0) o un código negativo
of_is_open ( ) → booleanVerdadero en cuanto existe la página oculta
of_hash (string as_algorithm, string as_text) → stringEl hash de un texto, en hexadecimal; HASH_* para el algoritmo. Vacío si falla
of_sha256 (string as_text) → stringof_hash con HASH_SHA256 — el que más se usa
of_hmac (string as_algorithm, string as_key, string as_text) → stringEl HMAC de un texto bajo una clave secreta, en hexadecimal — lo que una API pide para autenticar una llamada
of_hash_file (string as_algorithm, string as_path) → stringEl hash de un archivo del equipo, de cualquier tipo y hasta 512 MB, sin cargarlo en PowerBuilder
of_base64_encode (string as_text) → stringUn texto en base64 (sus bytes UTF-8): lo que un navegador o Python escribiría. Vacío en caso de fallo
of_base64_decode (string as_base64) → stringEl texto de vuelta; un valor que no es base64 devuelve una cadena vacía e is_last_error, nunca basura
of_base64_encode_file (string as_path) → stringLos bytes de un archivo del equipo en base64 — un adjunto, una imagen para una llamada JSON — hasta 512 MB, leídos por la DLL, nunca cargados en PowerBuilder
of_base64_decode_to_file (string as_base64, string as_path) → longEscribe los bytes de un valor base64 en un archivo — el adjunto con el que respondió una API. Devuelve 0 una vez escrito, -5 con una ruta vacía o un valor que no es base64, -4 si el archivo no se puede escribir
of_encrypt (string as_password, string as_text) → stringCifra un texto con una contraseña: una sola cadena base64 que guardar. Vacío si falla
of_decrypt (string as_password, string as_cipher) → stringEl texto de vuelta, con la misma contraseña. Contraseña errónea o valor alterado: cadena vacía e is_last_error, nunca basura
of_uuid ( ) → stringUn UUID aleatorio (versión 4)
of_random_hex (integer ai_bytes) → stringai_bytes bytes aleatorios (1 a 4096) en hexadecimal: una sal, un token
of_generate_keypair (integer ai_bits, ref string as_public_pem, ref string as_private_pem) → longUn par RSA en PEM (KEY_*). Devuelve 0 cuando ambas claves están rellenas, -4 si falla
of_sign (string as_private_pem, string as_text) → stringLa firma de un texto por la clave privada, en base64. Vacío si falla
of_verify (string as_public_pem, string as_text, string as_signature) → booleanVerdadero si la firma se hizo exactamente sobre este texto con la clave privada correspondiente; falso — no un error — si el texto cambió
of_generate_keypair (string as_kind, ref string as_public_pem, ref string as_private_pem) → long`Un par por TIPO: KEY_RSA_2048/3072/4096, KEY_EC_P256 (firmas cortas) o KEY_ED25519. Devuelve 0, -4 en caso de fallo
of_key_kind (string as_pem) → string`La familia de una clave PEM: rsa, ec-p256 o ed25519
of_base64url_encode (string as_text) → string`base64 seguro para URL (JWT, cadena de consulta)
of_base64url_decode (string as_base64url) → string`El texto de vuelta; vacío si no es base64url
of_hex_encode (string as_text) → string`Los bytes UTF-8 de un texto en hexadecimal
of_hex_decode (string as_hex) → string`El texto de vuelta; vacío si no es hexadecimal
of_random_password (integer ai_length, string as_charset) → string`Una contraseña aleatoria (4 a 256 caracteres) sobre un juego CHARSET_*, sin sesgo. Vacía con una longitud incorrecta
of_equals_constant_time (string as_a, string as_b) → boolean`Igualdad en tiempo constante: comparar un token o un código sin delatarlo
of_password_hash (string as_password) → string`Lo que se GUARDA para una contraseña: PBKDF2 con sal (il_pbkdf2_rounds), rondas y sal en el valor. Nunca el mismo resultado dos veces
of_password_verify (string as_password, string as_stored) → boolean`Verdadero si la contraseña es la del valor guardado, comparada en tiempo constante
of_totp_secret ( ) → string`Un secreto nuevo para los códigos de dos factores (RFC 6238), en base32
of_totp_code (string as_secret) → string`El código de seis dígitos del momento, el que muestra el autenticador
of_totp_verify (string as_secret, string as_code) → boolean`Verdadero si el código es el del momento, del paso anterior o del siguiente
of_totp_uri (string as_secret, string as_account, string as_issuer) → string`La URI otpauth:// para poner en un código QR e inscribir al usuario
of_generate_key ( ) → string`Una clave AES-256 nueva, 32 bytes en hexadecimal
of_encrypt_with_key (string as_key, string as_text) → string`AES-256-GCM con una clave EXPLÍCITA (hex o base64): base64 de nonce + cifrado + tag, lo que openssl o Python descifran
of_decrypt_with_key (string as_key, string as_cipher) → string`El texto de vuelta con la misma clave; vacío e is_last_error si no
of_rsa_encrypt (string as_public_pem, string as_text) → string`Un secreto corto cifrado hacia una clave PÚBLICA (RSA-OAEP): solo la privada lo lee
of_rsa_decrypt (string as_private_pem, string as_cipher) → string`El secreto de vuelta, con la clave privada
of_jwt_sign (string as_algorithm, string as_key, string as_claims_json, long al_expires_seconds) → string`Un JWT firmado: JWT_HS256 (secreto compartido), JWT_RS256/JWT_ES256/JWT_EDDSA (clave privada); iat añadido, exp si la duración es > 0. Vacío en caso de fallo
of_jwt_verify (string as_algorithm, string as_key, string as_token) → string`Los claims (JSON) de un token cuya firma, algoritmo y fechas son correctos; vacío e is_last_error si no
of_jwt_claims (string as_token) → string`Los claims SIN verificación, para leer a quién nombra el token antes de elegir la clave
of_protect (string as_text { , boolean ab_machine }) → string`Un secreto protegido por Windows para este usuario (o esta máquina): DPAPI, nativo. Lo que va en el INI para una contraseña de servidor
of_unprotect (string as_protected) → string`El texto de vuelta, en la misma cuenta; vacío e is_last_error en otra
of_crc32 (string as_text) → string`El CRC32 de un texto, 8 dígitos hexadecimales — un control de integridad, no un hash
of_crc32_file (string as_path) → string`El CRC32 de un archivo, leído por la DLL
of_encrypt_file (string as_password, string as_source, string as_target) → long`Un archivo cifrado por contraseña, en nativo (mismo contenedor que of_encrypt). Devuelve 0, -5 argumento vacío, -2 origen ilegible, -4 destino no escribible
of_decrypt_file (string as_password, string as_source, string as_target) → long`El archivo de vuelta. Devuelve 0, -3 contraseña incorrecta o archivo alterado (no se escribe nada), -5/-2/-4 como of_encrypt_file
of_close ( )Libera la página oculta; se hace por usted al destruir el objeto
of_reset ( )Vuelta a los valores por defecto

Ejemplos #

Comprobar que un archivo no ha cambiado #

string ls_expected, ls_actual
ls_expected = ProfileString("deploy.ini", "files", "orders.pbd", "")
ls_actual = lnv_crypto.of_hash_file(n_pbt_crypto.HASH_SHA256, "orders.pbd")
if ls_actual <> ls_expected then MessageBox("Deploy", "orders.pbd is not the file that was tested.")

Un adjunto en base64 para una API #

// Sending : the file's bytes in the JSON body
lnv_j.of_set_string("filename", "invoice_4152.pdf")
lnv_j.of_set_string("content", lnv_crypto.of_base64_encode_file("C:\invoices\4152.pdf"))
lnv_rest.of_post("https://api.example.com/documents", lnv_j.of_text())

// Receiving : the answer's attachment, back on disk
lnv_crypto.of_base64_decode_to_file(lnv_rest.of_json_value("content"), "C:\inbox\receipt.pdf")

Guardar un secreto en un INI #

// At setup : encrypt once, store the string
SetProfileString("app.ini", "db", "password", lnv_crypto.of_encrypt(ls_master, ls_db_password))

// At run time : the master password comes from the user, the INI gives the rest
ls_db_password = lnv_crypto.of_decrypt(ls_master, ProfileString("app.ini", "db", "password", ""))
if ls_db_password = "" then MessageBox("Login", lnv_crypto.is_last_error)

Firmar un pedido, verificarlo en otro sitio #

string ls_public, ls_private, ls_signature
lnv_crypto.of_generate_keypair(n_pbt_crypto.KEY_2048, ls_public, ls_private)   // once ; keep ls_private
ls_signature = lnv_crypto.of_sign(ls_private, ls_order_json)
// The public key and the signature travel with the order ; anyone can check :
if not lnv_crypto.of_verify(ls_public, ls_order_json, ls_signature) then MessageBox("Order", "This order was altered.")

Un token para una API, y su verificación #

// The client : a token valid one hour, in the Authorization header
ls_token = lnv_crypto.of_jwt_sign(n_pbt_crypto.JWT_HS256, ls_api_secret, '{"sub":"guillaume","role":"admin"}', 3600)
lnv_rest.of_set_bearer(ls_token)

// The server side (or a check of what came back) : the claims, once the signature and the expiry are right
ls_claims = lnv_crypto.of_jwt_verify(n_pbt_crypto.JWT_HS256, ls_api_secret, ls_token)
if ls_claims = "" then MessageBox("API", lnv_crypto.is_last_error)
ls_role = gnv_utils.of_json_get_str(ls_claims, "role")

Una contraseña de servidor guardada por Windows, y un usuario con dos factores #

// At setup : the INI holds a value Windows protects for this account, never the password
SetProfileString("app.ini", "db", "password", lnv_crypto.of_protect(ls_db_password))
// At run time
ls_db_password = lnv_crypto.of_unprotect(ProfileString("app.ini", "db", "password", ""))

// Enrolling a user : a secret in the database, the QR on screen
ls_secret = lnv_crypto.of_totp_secret()
uo_qr.is_data = lnv_crypto.of_totp_uri(ls_secret, ls_login, "MyApp")
// Logging in : the stored hash, then the six digits
if lnv_crypto.of_password_verify(ls_typed, ls_stored_hash) and lnv_crypto.of_totp_verify(ls_secret, ls_six_digits) then ...

Buenas prácticas #

← Referencia de componentes · Índice de la guía