PBToolboxAI v3 ← Site

crypto — n_pbt_crypto #

← Referência dos componentes · Índice do guia

Hashes, HMAC, cifra por palavra-passe, valores aleatórios e assinaturas RSA — a Web Crypto API do motor WebView2, que o seu PowerBuilder 10 não tem em mais lado nenhum. Sem DLL de terceiros, sem serviço: o que o posto já sabe fazer, oferecido ao PowerScript.

▶ Ver ao vivo — Aplicação de demonstração, mosaico Crypto: os resultados, o código que os produz e esta página, lado a lado.


Em resumo #

Objeto não visualn_pbt_crypto
Serve paraVerificar que um ficheiro não mudou, guardar um segredo num INI, assinar uma encomenda, autenticar uma chamada a uma API
PrincípioUma página oculta faz o cálculo; cada método é uma chamada PowerScript normal que devolve o seu valor
DependênciaO runtime WebView2, já exigido pela biblioteca — mais nada

Início 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 é uma chamada que devolve o seu valor: sem evento, sem espera a escrever.


Os formatos, legíveis pelas outras ferramentas #


Propriedades #

PropriedadeTipoPredefiniçãoFunção
is_last_errorstring""Porque a última chamada devolveu uma cadeia vazia, false ou um código negativo: palavra-passe errada, ficheiro ilegível, algoritmo desconhecido, limite demo
il_timeout_mslong20000Duração máxima de uma chamada. Calcular o hash de um ficheiro grande ou gerar uma chave de 4096 bits pode demorar alguns segundos
il_pbkdf2_roundslong100000Rondas PBKDF2 de of_encrypt, of_password_hash e of_encrypt_file: cerca de 100 ms. Mais é mais lento para todos, atacante incluído

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


Métodos #

MétodoFunção
of_open ( ) → longCria a página oculta. Facultativo — cada método fá-lo — mas chamá-lo ao abrir a janela paga o custo uma vez. Devolve o handle (> 0) ou um código negativo
of_is_open ( ) → booleanVerdadeiro assim que a página oculta existe
of_hash (string as_algorithm, string as_text) → stringO hash de um texto, em hexadecimal; HASH_* para o algoritmo. Vazio em caso de falha
of_sha256 (string as_text) → stringof_hash com HASH_SHA256 — o que mais se usa
of_hmac (string as_algorithm, string as_key, string as_text) → stringO HMAC de um texto com uma chave secreta, em hexadecimal — o que uma API pede para autenticar uma chamada
of_hash_file (string as_algorithm, string as_path) → stringO hash de um ficheiro do posto, de qualquer tipo e até 512 MB, sem o carregar no PowerBuilder
of_base64_encode (string as_text) → stringUm texto em base64 (os seus bytes UTF-8): o que um navegador ou o Python escreveria. Vazio em caso de falha
of_base64_decode (string as_base64) → stringO texto de volta; um valor que não é base64 devolve uma cadeia vazia e is_last_error, nunca lixo
of_base64_encode_file (string as_path) → stringOs bytes de um ficheiro do posto em base64 — um anexo, uma imagem para uma chamada JSON — até 512 MB, lidos pela DLL, nunca carregados no PowerBuilder
of_base64_decode_to_file (string as_base64, string as_path) → longEscreve os bytes de um valor base64 num ficheiro — o anexo com que uma API respondeu. Devolve 0 uma vez escrito, -5 num caminho vazio ou num valor que não é base64, -4 se o ficheiro não puder ser escrito
of_encrypt (string as_password, string as_text) → stringCifra um texto com uma palavra-passe: uma única cadeia base64 a guardar. Vazio em caso de falha
of_decrypt (string as_password, string as_cipher) → stringO texto de volta, com a mesma palavra-passe. Palavra-passe errada ou valor alterado: cadeia vazia e is_last_error, nunca lixo
of_uuid ( ) → stringUm UUID aleatório (versão 4)
of_random_hex (integer ai_bytes) → stringai_bytes bytes aleatórios (1 a 4096) em hexadecimal: um sal, um token
of_generate_keypair (integer ai_bits, ref string as_public_pem, ref string as_private_pem) → longUm par RSA em PEM (KEY_*). Devolve 0 quando ambas as chaves estão preenchidas, -4 em caso de falha
of_sign (string as_private_pem, string as_text) → stringA assinatura de um texto pela chave privada, em base64. Vazio em caso de falha
of_verify (string as_public_pem, string as_text, string as_signature) → booleanVerdadeiro se a assinatura foi feita exatamente sobre este texto pela chave privada correspondente; falso — não um erro — se o texto mudou
of_generate_keypair (string as_kind, ref string as_public_pem, ref string as_private_pem) → long`Um par por TIPO: KEY_RSA_2048/3072/4096, KEY_EC_P256 (assinaturas curtas) ou KEY_ED25519. Devolve 0, -4 em caso de falha
of_key_kind (string as_pem) → string`A família de uma chave PEM: rsa, ec-p256 ou ed25519
of_base64url_encode (string as_text) → string`base64 seguro para URL (JWT, query string)
of_base64url_decode (string as_base64url) → string`O texto de volta; vazio se não for base64url
of_hex_encode (string as_text) → string`Os bytes UTF-8 de um texto em hexadecimal
of_hex_decode (string as_hex) → string`O texto de volta; vazio se não for hexadecimal
of_random_password (integer ai_length, string as_charset) → string`Uma palavra-passe aleatória (4 a 256 caracteres) num conjunto CHARSET_*, sem viés. Vazia num comprimento errado
of_equals_constant_time (string as_a, string as_b) → boolean`Igualdade em tempo constante: comparar um token ou um código sem o trair
of_password_hash (string as_password) → string`O que se GUARDA para uma palavra-passe: PBKDF2 com sal (il_pbkdf2_rounds), rondas e sal no valor. Nunca o mesmo resultado duas vezes
of_password_verify (string as_password, string as_stored) → boolean`Verdadeiro se a palavra-passe é a do valor guardado, comparada em tempo constante
of_totp_secret ( ) → string`Um segredo novo para os códigos de dois fatores (RFC 6238), em base32
of_totp_code (string as_secret) → string`O código de seis dígitos do momento, o que o autenticador mostra
of_totp_verify (string as_secret, string as_code) → boolean`Verdadeiro se o código é o do momento, do passo anterior ou do seguinte
of_totp_uri (string as_secret, string as_account, string as_issuer) → string`O URI otpauth:// a colocar num código QR para inscrever o utilizador
of_generate_key ( ) → string`Uma chave AES-256 nova, 32 bytes em hexadecimal
of_encrypt_with_key (string as_key, string as_text) → string`AES-256-GCM com uma chave EXPLÍCITA (hex ou base64): base64 de nonce + cifrado + tag, o que o openssl ou o Python decifram
of_decrypt_with_key (string as_key, string as_cipher) → string`O texto de volta com a mesma chave; vazio e is_last_error caso contrário
of_rsa_encrypt (string as_public_pem, string as_text) → string`Um segredo curto cifrado para uma chave PÚBLICA (RSA-OAEP): só a privada o lê
of_rsa_decrypt (string as_private_pem, string as_cipher) → string`O segredo de volta, com a chave privada
of_jwt_sign (string as_algorithm, string as_key, string as_claims_json, long al_expires_seconds) → string`Um JWT assinado: JWT_HS256 (segredo partilhado), JWT_RS256/JWT_ES256/JWT_EDDSA (chave privada); iat acrescentado, exp se a duração for > 0. Vazio em caso de falha
of_jwt_verify (string as_algorithm, string as_key, string as_token) → string`Os claims (JSON) de um token cuja assinatura, algoritmo e datas estão certos; vazio e is_last_error caso contrário
of_jwt_claims (string as_token) → string`Os claims SEM verificação, para ler quem o token nomeia antes de escolher a chave
of_protect (string as_text { , boolean ab_machine }) → string`Um segredo protegido pelo Windows para este utilizador (ou esta máquina): DPAPI, nativo. O que se guarda no INI para uma palavra-passe de servidor
of_unprotect (string as_protected) → string`O texto de volta, na mesma conta; vazio e is_last_error noutro lado
of_crc32 (string as_text) → string`O CRC32 de um texto, 8 dígitos hexadecimais — um controlo de integridade, não um hash
of_crc32_file (string as_path) → string`O CRC32 de um ficheiro, lido pela DLL
of_encrypt_file (string as_password, string as_source, string as_target) → long`Um ficheiro cifrado por palavra-passe, em nativo (mesmo contentor que of_encrypt). Devolve 0, -5 argumento vazio, -2 origem ilegível, -4 destino não gravável
of_decrypt_file (string as_password, string as_source, string as_target) → long`O ficheiro de volta. Devolve 0, -3 palavra-passe errada ou ficheiro alterado (nada é escrito), -5/-2/-4 como of_encrypt_file
of_close ( )Liberta a página oculta; feito por si ao destruir o objeto
of_reset ( )Regresso aos valores por defeito

Exemplos #

Verificar que um ficheiro não mudou #

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.")

Um anexo em base64 para uma 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 um segredo num 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)

Assinar uma encomenda, verificá-la noutro lado #

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.")

Um token para uma API, e a sua verificação #

// 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")

Uma palavra-passe de servidor guardada pelo Windows, e um utilizador com dois fatores #

// 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 ...

Boas práticas #

← Referência dos componentes · Índice do guia