基于Google/Tink的密码加密数据库存储问题咨询
Hey there! I see you're running into trouble when storing encrypted passwords from Google Tink in your database—let's break this down and fix it.
The Root Problem
When you encrypt a password with Tink, you get a raw byte[] (binary data). If you directly convert this byte array to a string using something like new String(ciphertext), you're asking Java to interpret those binary bytes as characters using a default encoding (like UTF-8). The issue? Not all binary values map to valid UTF-8 characters, so this conversion will corrupt or lose data. When you pull that corrupted string back from the database, you won't be able to decrypt it properly.
The Solution: Encode Binary Data to a Safe String Format
You need to convert the raw binary ciphertext into a string using an encoding that preserves all data. Two common, reliable options are Base64 or Hexadecimal (Hex) encoding—both turn binary data into printable ASCII characters that databases handle perfectly.
Option 1: Base64 Encoding (Most Common)
Base64 is widely supported and produces relatively compact strings. Here's how to integrate it with your existing Tink code:
import java.util.Base64; // After encrypting to get ciphertext byte[] String ciphertextStr = Base64.getEncoder().encodeToString(ciphertext); // Store ciphertextStr in your database as a regular string // When retrieving from the database to decrypt String storedCiphertext = ...; // Get from DB byte[] ciphertextBytes = Base64.getDecoder().decode(storedCiphertext); byte[] plaintext = aead.decrypt(ciphertextBytes, aad); // Use same AAD as encryption!
Option 2: Hexadecimal Encoding
Hex encodes each byte as two hex characters (0-9, A-F), which is more verbose but easy to read if you ever need to inspect the data. Using Java's built-in tools:
import javax.xml.bind.DatatypeConverter; // Encrypt then convert to Hex string String ciphertextHex = DatatypeConverter.printHexBinary(ciphertext); // Store ciphertextHex in your database // Retrieve and convert back to byte[] String storedHex = ...; // Get from DB byte[] ciphertextBytes = DatatypeConverter.parseHexBinary(storedHex); byte[] plaintext = aead.decrypt(ciphertextBytes, aad);
Critical Extra Notes
- Never skip AAD: Always use the same Associated Authenticated Data (AAD) value during encryption and decryption. A great practice is to use a unique identifier for the user (like their user ID) as AAD—this adds an extra layer of security, ensuring a ciphertext can only be decrypted for the intended user.
- Secure your keys: Your
KeysetHandlecontains sensitive encryption keys. Never hardcode it, store it in plaintext, or commit it to version control. Use Tink's built-in key management tools (likeKeysetManager) or integrate with a Key Management Service (KMS) to encrypt and store your keys securely.
内容的提问来源于stack exchange,提问作者Manish Mehta




