Converting Amazon AWS keys for use with SES - java

I've been attempting to convert my Amazon Web Services IAM key for use with SES and I haven't been able to successfully authenticate with the code that I'm using.
I've taken the algorithm from the official documentation and attempted to convert it to Python. While I believe that I have done this correctly, this could definitely use a review.
The documentation example code (as it is written in Java) is as follows:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class SesSmtpCredentialGenerator {
private static final String KEY = "AWS SECRET ACCESS KEY"; // Replace with your AWS Secret Access Key.
private static final String MESSAGE = "SendRawEmail"; // Used to generate the HMAC signature. Do not modify.
private static final byte VERSION = 0x02; // Version number. Do not modify.
public static void main(String[] args) {
// Create an HMAC-SHA256 key from the raw bytes of the AWS Secret Access Key
SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes(), "HmacSHA256");
try {
// Get an HMAC-SHA256 Mac instance and initialize it with the AWS secret access key.
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKey);
// Compute the HMAC signature on the input data bytes.
byte[] rawSignature = mac.doFinal(MESSAGE.getBytes());
// Prepend the version number to the signature.
byte[] rawSignatureWithVersion = new byte[rawSignature.length + 1];
byte[] versionArray = {VERSION};
System.arraycopy(versionArray, 0, rawSignatureWithVersion, 0, 1);
System.arraycopy(rawSignature, 0, rawSignatureWithVersion, 1, rawSignature.length);
// To get the final SMTP password, convert the HMAC signature to base 64.
String smtpPassword = DatatypeConverter.printBase64Binary(rawSignatureWithVersion);
System.out.println(smtpPassword);
} catch (Exception ex) {
System.out.println("Error generating SMTP password: " + ex.getMessage());
}
}
}
and here is the code that I have written:
def hash_IAM(user_password):
#http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html
if DEBUG: debug_message("Hashing for IAM to SES values")
#Pseudocode:
#encrypted_intent = HmacSha256("SendRawEmail", "AWS Secret Key")
#encrypted_intent = concat(0x02, encrypted_intent)
#resultant_password = Base64(encrypted_intent)
#private static final String KEY = "AWS SECRET ACCESS KEY";
AWS_SECRET_ACCESS_KEY = user_password
# private static final String MESSAGE = "SendRawEmail";
AWS_MESSAGE = "SendRawEmail"
#private static final byte VERSION = 0x02;
#see chr(2) below.
#SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes(), "HmacSHA256");
#Mac mac = Mac.getInstance("HmacSHA256");
#mac.init(secretKey);
#If I understand correctly, SecretKeySpec is just a vessel for the key and a str that mac.init expects..
#http://developer.android.com/reference/javax/crypto/spec/SecretKeySpec.html [(key data), (algorithm)]
#http://docs.oracle.com/javase/7/docs/api/javax/crypto/Mac.html#init(java.security.Key, java.security.spec.AlgorithmParameterSpec)
#in Python 2, str are bytes
signature = hmac.new(
key=AWS_SECRET_ACCESS_KEY,
msg=AWS_MESSAGE,
digestmod=hashlib.sha256
).digest()
# Prepend the version number to the signature.
signature = chr(2) + signature
# To get the final SMTP password, convert the HMAC signature to base 64.
signature = base64.b64encode(signature)
return signature
And I've given myself very-open IAM group permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:*"
],
"Resource": "*"
}
]
}
I'm hoping that someone can spot an issue in my code or knows something about the API that I was not able to find via Google searches.
Update: I compiled the Java version and my output matches that of a test string. Ostensibly, my Python version is correct, but I'm still getting exceptions of type SMTPAuthenticationError.

Related

Encode/Decode SHA256WITHECDSA - nodeJS

I'm trying to decode/encode a signature with SHA256withECDSA.
I have a Java code that works fine:
public void verify() throws Exception {
Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA"));
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode("your public key goes here"));
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update("All the webhook field values (only the values) concatenated together using a semicolon ;".getBytes("UTF-8"));
boolean result = ecdsaVerify.verify(Base64.getDecoder().decode("Signature to verify")); //Must return true
}
but I need this solution for nodejs.
when I'm creating an base64 buffer in nodejs it's getting a different results from the Java code.
I currently use cryptojs & jwa npm's.
Edit:
this is my code for nodejs:
var jwa = require("jwa");
const verifySignature = () => {
let public_key = Buffer.from("public key here", "base64");
let signature = Buffer.from("Signature_here", "base64");
let payload = "data here seperated by semicolon";
let ecdsa = jwa("ES256");
let verify = ecdsa.verify(payload, signature, public_key);
}
verifySignature();
JWA implements the algorithms used in JOSE, and in particular for ECDSA uses the signature format (aka encoding) defined in P1363 that simply contains fixed-length R and S concatenated; see steps 2 and 3 of https://datatracker.ietf.org/doc/html/rfc7518#section-3.4 . This is not the format used by most other standards, and in particular by Java, which is an ASN.1 DER-encoded SEQUENCE of two INTEGER values, which are (both) variable length (all) with tag and length prefixes.
You don't need JWA at all; builtin 'crypto' has the functionality you need:
import java.security.KeyFactory;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class SO70655734 {
public static void main (String[] args) throws Exception {
String data = "some;test;data";
String pubkey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyOFORyCVCxX+W4QZevzH6skTbp2lVDtRLV0+7ypHjX26wFtSWSe4MTI0GZjIKDOAIT8KpbqH8HXI6Wo5S6/6hg==";
String sig = "MEQCICDLwztlKOXmQLuDJ0Hh96gGAT2/wsm2ymw3CDxSDnB3AiAK7eR8+C6g/zw5TmXUX0K/pV5kjIJTCieIkQXzH30WYA==";
Signature ecdsa = Signature.getInstance("SHA256withECDSA");
ecdsa.initVerify(KeyFactory.getInstance("EC").generatePublic(
new X509EncodedKeySpec(Base64.getDecoder().decode(pubkey)) ));
ecdsa.update(data.getBytes("UTF-8")); // or StandardCharsets.UTF_8
System.out.println(ecdsa.verify(Base64.getDecoder().decode(sig)));
}
}
-> true
const crypto = require('crypto');
const data = "some;test;data";
const pubkey = "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyOFORyCVCxX+W4QZevzH6skTbp2lVDtRLV0+7ypHjX26wFtSWSe4MTI0GZjIKDOAIT8KpbqH8HXI6Wo5S6/6hg==\n"
+ "-----END PUBLIC KEY-----\n";
const sig = "MEQCICDLwztlKOXmQLuDJ0Hh96gGAT2/wsm2ymw3CDxSDnB3AiAK7eR8+C6g/zw5TmXUX0K/pV5kjIJTCieIkQXzH30WYA==";
var ecdsa = crypto.createVerify('SHA256');
ecdsa.update(data,'utf8');
console.log( ecdsa.verify(pubkey, sig,'base64') );
-> true
Note: recent versions of nodejs can instead take DER-format pubkey (without the BEGIN/END lines added, but with the base64 converted to binary), but my most convenient test system only has 8.10.0 so I went the more compatible old way.

(Java to Javascript) javax.crypto.Cipher equivalent code in Nodejs Crypto Javascript

I'm trying to convert below java code into nodejs.
private static String TRANS_MODE = "Blowfish";
private static String BLOWFISH_KEY = "BLOWFISH_KEY";
public static String encrypt(String password) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(BLOWFISH_KEY.getBytes("Windows-31J"),TRANS_MODE);
Cipher cipher;
cipher = Cipher.getInstance(TRANS_MODE);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] passByte;
passByte = cipher.doFinal(password.getBytes("Windows-31J"));
return new String(Hex.encodeHex(passByte));
}
Here is what I was able to figure out-
const crypto = require('crypto');
function encrypt(password)
var fcKey = "BLOWFISH_KEY";
var cipher = crypto.createCipher('BF-CBC', fcKey, "");
var encrypted = cipher.update(password,'ascii','hex');
encrypted += cipher.final('hex');
return encrypted;
I'm not able to get same output. For example if
password= "password01"
Java Code output - fe0facbf8d458adaa47c5fe430cbc0ad
Nodejs Code output - ae5e8238c929b5716566e97fa35efb9b
Can someone help me figure out the problem ??
Notice that crypto.createCipher(algorithm, password[, options]) is deprecated and should not be used.
Where the SecretKeySpec(..) in java takes a binary key as input, the createCipher(..) in js takes a "password" as input, and behind the scene tries to derive a binary key using MD5. So your actually key used in the two programs ends up being different. The js methode
also tries to derive an IV from the password, which is bad practice and different from your java code.
In js you need to use the crypto.createCipheriv() instead. And when you are at it, you also need to consider if an iv is needed - both in Java and in js.

Implement Diffie-Hellman key exchange in Java

I am trying to implement Diffie-Hellman key exchange in Java, but I'm having a hard time understanding the specification:
Complete the Diffie-Hellman key exchange process as a local mechanism
according to JWA (RFC 7518) in Direct Key Agreement mode using curve
P-256, dT and QC to produce a pair of CEKs (one for each direction)
which are identified by Transaction ID. The parameter values supported
in this version of the specification are:
“alg”: ECDH-ES
“apv”: SDK Reference Number
“epk”: QC, in JSON Web Key (JWK) format
{“kty”:”EC” “crv”:“P-256”}
All other parameters: not present
CEK: “kty”:oct - 256 bits
Create a JSON object of the following data as the JWS payload to be
signed:
{“MyPublicKey”: “QT”, “SDKPublicKey”:” QC”}
Generate a digital signature of the full JSON object according to JWS
(RFC 7515) using JWS Compact Serialization. The parameter values
supported in this version of the specification are:
“alg”: PS256 or ES256
“x5c”: X.5C v3: Cert(MyPb) plus optionally chaining certificates
From my understanding, ECDH will produce a secret key. After sharing my ephemeral public key (QT), the SDK produces the same secret key, so we can later exchange JWE messages encrypted with the same secret key.
The JSON {“MyPublicKey”: “QT”, “SDKPublicKey”:” QC”} will be signed and sent, but I do not understand how I will use apv and epk since these header params are used in JWE and not in the first JWS to be shared.
On the same specification, they talk about these JWE messages, but they do not have these apv and epk parameters.
Encrypt the JSON object according to JWE (RFC 7516) using the same
“enc” algorithm used by the SDK, the CEK obtained identified by “kid”
and JWE Compact Serialization. The parameter values supported in this
version of the specification are:
“alg”: dir
“enc”: either A128CBC-HS256 or A128GCM
“kid”: Transaction ID
All other parameters: not present
I also read the example in RFC 7518 where I can see the header params apv and epk being used but I'm not sure which header params, JWE's or JWS's ?
Any thought on how this could be implemented using nimbus-jose-jwt or any other java library would be really helpful. Thanks
Both apv (Agreement PartyVInfo) and epk (Ephemeral Public Key) are optional, so they can be used in multiple ways. You can use apv to reflect SDK version for example. They are added to the JWE header.
You can read more about JWE in Nimbus here
An example using Nimbus JOSE would be:
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.nimbusds.jose.*;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.KeyOperation;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.util.Base64;
import com.nimbusds.jose.util.Base64URL;
public class Security {
public void generateJWE() throws JOSEException, URISyntaxException {
JWEHeader jweHeader = buildJWEHeader(new Base64URL("202333517"), buildECKey());
JWEObject jweObject = new JWEObject(jweHeader, new Payload("Hello World!"));
}
private JWEHeader buildJWEHeader(Base64URL apv, ECKey epk) {
JWEHeader.Builder jweBuilder = new JWEHeader.Builder(JWEAlgorithm.ECDH_ES, EncryptionMethod.A128GCM);
jweBuilder.agreementPartyVInfo(apv);
jweBuilder.ephemeralPublicKey(epk);
return jweBuilder.build();
}
private ECKey buildECKey() throws URISyntaxException {
Set<KeyOperation> keyOperations = new HashSet<>();
keyOperations.add(KeyOperation.ENCRYPT);
String transactionID = "73024831";
URI x5u = new URI("https//website.certificate");
KeyStore keystore = null; //initialize it
List<Base64> x5c = new ArrayList<>();
return new ECKey(Curve.P_256, new Base64URL("x"), new Base64URL("y"), KeyUse.ENCRYPTION, keyOperations, Algorithm.NONE, transactionID, x5u, new Base64URL("x5t"), new Base64URL("x5t256"), x5c, keystore);
}
}
Instead of EncryptionMethod.A128GCM you can use EncryptionMethod.A128CBC-HS256 as in your specification. apv and epk are added to JWEHeader inside builder.
Other parameters can be chosen in constructors of JWEHeader.Builder and ECKey. I used ECDH-ES algorithm, A128GCM encryption method, P-256 curve (elliptic curve is default in ECKey generation),
transaction ID is a string. I chose other parameters without any clear pattern. Initialization of KeyStore would be too broad for the example. Encryption is only one thing you can do with JWE, among signature and others.
Nimbus (as well as Jose4j) is not the best choice for implementing the specification (I guess it's 3D secure 2.x.x).
These libraries do not return content encrypion key but use it to encrypt or decrypt messages as per JWE spec.
I found that Apache CXF Jose library does its job well as a JWE/JWS/JWK implementation. Except generating ephemeral key pairs. But it's can easily be done with Bouncy Castle:
Security.addProvider(new BouncyCastleProvider());
ECGenParameterSpec ecGenSpec = new ECGenParameterSpec(JsonWebKey.EC_CURVE_P256);
KeyPairGenerator g = KeyPairGenerator.getInstance(ALGORITHM_SIGNATURE_EC, "BC");
g.initialize(ecGenSpec, new SecureRandom());
KeyPair keyPair = g.generateKeyPair();
Content encrypion key can be produced with this code:
byte[] cek = JweUtils.getECDHKey(privateKey, publicKey, null, SDKReferenceNumber, "", 256);
And used to encrypt messages getting JWE compact representation:
JweEncryption jweEncryption = JweUtils.getDirectKeyJweEncryption(cek, contentAlgorithm);
JweHeaders head = new JweHeaders();
head.setHeader(JoseConstants.HEADER_KEY_ID, keyId);
String encrypted = jweEncryption.encrypt(contentToEncrypt.getBytes(StandardCharsets.UTF_8), head);
Or decrypt:
JweCompactConsumer compactConsumer = new JweCompactConsumer(encrypted);
JweHeaders head = compactConsumer.getJweHeaders();
JweDecryption jweDecryption = JweUtils.getDirectKeyJweDecryption(cek, head.getContentEncryptionAlgorithm());
JweDecryptionOutput out = jweDecryption.decrypt(encrypted);
String decrypted = out.getContentText();
I able to generate the Secret Key for A128CBC-HS256. However still not succeed in A128GCM. Adding the working sample for A128CBC-HS256 with help nimbus-jose library. This below code is only for key generation.
Please also note that I override the nimbus-jose classes for my usage. Hope it helps.
private void generateSHA256SecretKey(AREQ areq, ECKey sdkPubKey, KeyPair acsKeyPair) throws Exception {
// Step 4 - Perform KeyAgreement and derive SecretKey
SecretKey Z = CustomECDH.deriveSharedSecret(sdkPubKey.toECPublicKey(), (ECPrivateKey)acsKeyPair.getPrivate(), null);
CustomConcatKDF concatKDF = new CustomConcatKDF("SHA-256");
String algIdString = "";
String partyVInfoString = areq.getSdkReferenceNumber();
int keylength = 256; //A128CBC-HS256
byte[] algID = CustomConcatKDF.encodeDataWithLength(algIdString.getBytes(StandardCharsets.UTF_8));
byte[] partyUInfo = CustomConcatKDF.encodeDataWithLength(new byte[0]);
byte[] partyVInfo = CustomConcatKDF.encodeDataWithLength(partyVInfoString.getBytes(StandardCharsets.UTF_8));
byte[] suppPubInfo = CustomConcatKDF.encodeIntData(keylength);
byte[] suppPrivInfo = CustomConcatKDF.encodeNoData();
SecretKey derivedKey = concatKDF.deriveKey(
Z,
keylength,
algID,
partyUInfo,
partyVInfo,
suppPubInfo,
suppPrivInfo);
System.out.println("Generated SHA256 DerivedKey : "+SecureUtils.bytesToHex(derivedKey.getEncoded()));
}

UWP Standard CMS Enveloped Encryption

I need to implement AES Encryption Algorithm in Cryptographic Message Syntax (CMS) standard to encrypt my data in Windows Universal App (found reference here). I have it implemented on Java using Bouncy Castle library using the following code(I need the same functionality in C# UWP):
private static final ASN1ObjectIdentifier CMS_ENCRYPTION_ALGO = CMSAlgorithm.AES256_CBC;
private byte[] encrypt(byte[] key, byte[] dataToBeEncrypted) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, CMSException {
final KeySpec keySpec = new X509EncodedKeySpec(key);
final KeyFactory factory = KeyFactory.getInstance("RSA");
final PublicKey publicKey = factory.generatePublic(keySpec);
final SubjectKeyIdentifier subjectKeyIdentifier = new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey);
final RecipientInfoGenerator recipientInfoGenerator = new JceKeyTransRecipientInfoGenerator(subjectKeyIdentifier.getEncoded(), publicKey);
final CMSEnvelopedDataGenerator generator = new CMSEnvelopedDataGenerator();
generator.addRecipientInfoGenerator(recipientInfoGenerator);
final OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMS_ENCRYPTION_ALGO).build();
final CMSProcessableByteArray content = new CMSProcessableByteArray(dataToBeEncrypted);
final CMSEnvelopedData envelopedData = generator.generate(content, encryptor);
return envelopedData.toASN1Structure().getEncoded(ASN1Encoding.DER);
}
Now I have Referenced Bouncy Castle V 1.8.1 in my UWP App, but I found many differences (some libraries used in Java but not exist in Windows) and couldn't implement such functionality in C#.
So kindly either guide me to implement the same using native UWP Cryptography Library Windows.Security.Cryptography (Preferred),
Or tell me how can I implement same functionality using Bouncy Castle 1.8.1 in C# UWP app.
Update:
Based on the following diagram from here, I understand that the required steps are:
1- Get the data and generate Symmetric Key to encrypt the data using algorithm AesCbcPkcs7.
2- Encrypt Symmetric Key using the public key
3- Generate Digitally enveloped message.
So I did the first two steps based on my understanding using the following c# code (Please correct me if I'm wrong) and I need help to do the third step:
public string EncryptAndEnvelope(string openText, string p_key)
{
// Step 1 Get the data and generate Symmetric Key to encrypt the data using algorithm AesCbcPkcs7
IBuffer cBuffer = CryptographicBuffer.GenerateRandom(32);
SymmetricKeyAlgorithmProvider provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
CryptographicKey m_key = provider.CreateSymmetricKey(cBuffer);
IBuffer bufferMsg = CryptographicBuffer.ConvertStringToBinary(AsciiToString(StringToAscii(openText)), BinaryStringEncoding.Utf8);
IBuffer bufferEncrypt = CryptographicEngine.Encrypt(m_key, bufferMsg, null);
// Step 2 Encrypt Symmetric Key using the public key
IBuffer publicKey = CryptographicBuffer.DecodeFromBase64String(p_key);
AsymmetricKeyAlgorithmProvider asym = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey ckey = asym.ImportPublicKey(publicKey, CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo);
IBuffer cbufferEncrypt = CryptographicEngine.Encrypt(ckey, cBuffer, null);
// Step 3 Generate Digitally enveloped message
// I need help here
}
private byte[] StringToAscii(string s)
{
byte[] retval = new byte[s.Length];
for (int ix = 0; ix < s.Length; ++ix)
{
char ch = s[ix];
if (ch <= 0x7f) retval[ix] = (byte)ch;
else retval[ix] = (byte)'?';
}
return retval;
}
private string AsciiToString(byte[] bytes)
{
return string.Concat(bytes.Select(b => b <= 0x7f ? (char)b : '?'));
}
Note: While I was looking for solution, I've found that the answer is available using the library System.Security.Cryptography
(but it is not supported in Universal Apps) and I'm pretty sure that
the implementation is available using Bouncy Castle (there are
tons of documentation for Java but unfortunately there is no
documentation at all for C#).

Encrypt content with php and java

I have an app with java and PHP files. The java files send content to the PHP files, and this one send the response to the java file, by HTTP everything. I have the response with JSON format.
I would like to encrypt the information and decode it in the other side, java->php and php->java(this is the most important) but I don't know how to do it.
Edit:
I am trying BLOWFISH, here is my code in PHP(crypt the data and send to Java) and Java(get the data and decode it)
PHP
$key = "this is the key";
$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $result_json, MCRYPT_MODE_ECB);
echo($crypttext);
JAVA
public String decryptBlowfish(String to_decrypt, String strkey) {
System.out.println(to_decrypt);
try {
SecretKeySpec key = new SecretKeySpec(strkey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(to_decrypt.getBytes());
return new String(decrypted);
} catch (Exception e) {
System.out.println(e.getMessage());
;
return null;
}
}
System.out.println(decryptBlowfish(result, "this is the key"));
The result when I execute is:
Input length must be multiple of 8 when encrypting with padded cipher
or sometimes
Given final block not properly padded
Agreed with the comment that's what SSL is for see here for a client java application that uses SSL Certificate and encryption to connect to an HTTPS/SSL site: http://www.mkyong.com/java/java-https-client-httpsurlconnection-example/ next you might want to have an HTTPS/SSL php server this should help: http://cweiske.de/tagebuch/ssl-client-certificates.htm Or use this Opensource library: http://nanoweb.si.kz/
If the above fails then I don't know, but a last resort would be writing your own, you may never know how secure it really is?
You might want to use the same algorithm for decoding/decrypting namely "blowfish/ecb/nopadding" instead of "blowfish".
private static final String DECRYPTION_ALGORITHM = "blowfish/ecb/nopadding";
private static final String KEY_ALGORITHM = "blowfish";
private static byte[] decrypt(byte[] keyData, byte[] valueData) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(keyData, KEY_ALGORITHM);
Cipher cipher = Cipher.getInstance(DECRYPTION_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
return cipher.doFinal(valueData);
}
If you don't want SSL, which I recommend too, you can try this:
$str = 'hello world'; //your input data
$pass = 'haj83kdj843j'; //something random, the longer the better
$l = strlen($pass);
for ($i=0; $i<strlen($str); $i++)
{
$str[$i] = chr(ord($str[$i]) + ord($pass[$i % $l]));
}
It is fast and easy to write a coder/encoder in any language you want. The resulting string is a binary string so you might want to convert it using base64_encode or something. Should give quite good security.

Categories