I've used file_get_contents for reading a WAV file in PHP and I want to use package github.com/mjibson/go-dsp/wav for same task in Go. But there is not any simple example about this package. I am new to Go and do not understand it. Is there anyone guiding me or suggest another way?
Code in PHP:
$wsdl = 'http://myApi.asmx?WSDL';
$client = new SoapClient($wsdl));
$data = file_get_contents(public_path() . "/forTest/record.wav");
$param = array(
'userName' => '***',
'password' => '***',
'file' => $data);
$res = $client->UploadMessage($param);
It looks like you do not need to use this package github.com/mjibson/go-dsp/wav. file_get_contents function is the preferred way to read the contents of a file into a string.
In Go, you can do something like this:
package main
import (
"fmt"
"io/ioutil"
)
func public_path() string {
return "/public/path/"
}
func main() {
dat, err := ioutil.ReadFile(public_path() + "/forTest/record.wav")
if err != nil {
fmt.Println(err)
}
fmt.Print(string(dat))
}
https://play.golang.org/p/l9R0940iK50
I think you just need to read the file, it really does not matter whether it is .wav or some other file. You can use go's builtin package io/ioutil.
Following is what you should do in go to read a disk file:
package main
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
// Reading .wav file from disk.
fileData, err := ioutil.ReadFile("DISK_RELATIVE_PATH_PREFIX" + "/forTest/record.wav")
// ioutil.ReadFile returns two results,
// first one is data (slice of byte i.e. []byte) and the other one is error.
// If error is having nil value, you got successfully read the file,
// otherwise you need to handle the error.
if err != nil {
// Handle error here.
log.Fatal(err)
} else {
// Do whatever needed with the 'fileData' such as just print the data,
// or send it over the network.
fmt.Print(fileData)
}
}
Hope this helps.
Given a WAV file this returns its payload as a floating point audio curve along with essential audio file details like bit-depth, sample-rate and num-channels.
Had you simply read in the binary audio file using one of the underlying IO primitives in order to obtain the audio curve you would have to battle with your own bit shifting to pluck multi-byte ints as well as handling big or little endianness.
You still must be aware of how to handle multi-channel interleaving of audio samples from each channel which is not an issue for mono audio.
package main
import (
"fmt"
"os"
"github.com/youpy/go-wav"
"math"
)
func read_wav_file(input_file string, number_of_samples uint32) ([]float64, uint16, uint32, uint16) {
if number_of_samples == 0 {
number_of_samples = math.MaxInt32
}
blockAlign := 2
file, err := os.Open(input_file)
if err != nil {
panic(err)
}
reader := wav.NewReader(file)
wavformat, err_rd := reader.Format()
if err_rd != nil {
panic(err_rd)
}
if wavformat.AudioFormat != wav.AudioFormatPCM {
panic("Audio format is invalid ")
}
if int(wavformat.BlockAlign) != blockAlign {
fmt.Println("Block align is invalid ", wavformat.BlockAlign)
}
samples, err := reader.ReadSamples(number_of_samples) // must supply num samples w/o defaults to 2048
// // just supply a HUGE number then actual num is returned
wav_samples := make([]float64, 0)
for _, curr_sample := range samples {
wav_samples = append(wav_samples, reader.FloatValue(curr_sample, 0))
}
return wav_samples, wavformat.BitsPerSample, wavformat.SampleRate, wavformat.NumChannels
}
func main() {
input_audio := "/blah/genome_synth_evolved.wav"
audio_samples, bits_per_sample, input_audio_sample_rate, num_channels := read_wav_file( input_audio, 0)
fmt.Println("num samples ", len(audio_samples)/int(num_channels))
fmt.Println("bit depth ", bits_per_sample)
fmt.Println("sample rate ", input_audio_sample_rate)
fmt.Println("num channels", num_channels)
}
Related
How I can read conditions unserialised data in golang in map format?
[map[19:map[conditions:map[0:map[operator:== value:AMW-1900-50SLE-ROOM
is_value_processed:false type:feedexport/rule_condition_product
attribute:sku] 1:map[type:feedexport/rule_condition_product
attribute:sku operator:== value:ASL-B654-77-74-98-ROOM
is_value_processed:false] 2:map[is_value_processed:false
type:feedexport/rule_condition_product attribute:sku operator:==
value:ASL-B217-57-54S-95-ROOM]] type:feedexport/rule_condition_combine
attribute:<nil> operator:<nil> value:1 is_value_processed:<nil>
aggregator:any]]]
This is the code:
package main
import (
"fmt"
"github.com/wulijun/go-php-serialize/phpserialize"
)
func main() {
rules := RulesList()
for _, rule := range rules{
fmt.Println(rule.Conditions.(interface{}))
}
}
type Rule struct {
RuleId int `json:"rule_id"`
Conditions interface{} `json:"conditions"`
}
func RulesList() ([]Rule) {
db := DbConn()
res, err := db.Query(`SELECT r.rule_id, r.conditions_serialized AS
conditions FROM m_feedexport_rule AS r`)
CheckError(err)
rule := Rule{}
rules := []Rule{}
for res.Next() {
var ruleId int
var conditions string
err = res.Scan(&ruleId, &conditions)
CheckError(err)
cons, err := phpserialize.Decode(conditions)
CheckError(err)
rule.RuleId = ruleId
rule.Conditions = cons
rules = append(rules, rule)
}
return rules
}
The result is ok but I need it in map form, now this is the interface which I can't loop over. In case if anyone don't understand the code, ask me.
Thanks a lot.
You're talking about the type of the variable cons, are you?
Background
If yes, the reason its type is interface{} is because in PHP, it's possible to serialize a value of any type (from bare integer to a complicated object), and hence any deserialization code must cope with it. Since in Go the so-called "empty interface", interface{},
is satisfied by any type at all (including any custom type implemented by a programmer), it's sensbile for a decoder of PHP-serialized data to return a value of type interface{}.
Solution
After making sure decoding succeeded,
you need to either type-assert
the resulting value to a type you need or to use
a type switch
to diverge processing based on the concrete type of the
value returned by the decoder.
The approach is very well demonstrated by the
package you're using in its own test suite.
A snippet from it demonstrating the basic approach
if decodeRes, err = Decode(result); err != nil {
t.Errorf("decode data fail %v, %v", err, result)
return
}
decodeData, ok := decodeRes.(map[interface{}]interface{})
if !ok {
t.Errorf("decode data type error, expected: map[interface{}]interface{}, get: %T", decodeRes)
return
}
obj, _ := decodeData["object"].(*PhpObject)
if v, _ := obj.GetPrivateMemberValue("a"); v != int64(1) {
t.Errorf("object private value expected 1, get %v, %T", v, v)
}
if v := obj.GetClassName(); v != "A" {
t.Errorf("object class name expected A, get %v", v)
}
Here, decodeRes is what returned by the decoder.
That value is then type-asserted to make sure it's concrete type
(also called "dynamic" — meaning "at runtime") is
map[interface{}]interface{}.
Note that the so-called "two-argument" type assert is used
(it's also called a "comma-ok idiom") to not make the program
panic at runtime in case the concrete type is different from
the expected (always do this on data fetched from outside!).
The value of the type-asserted concrete type is stored in the
decodeData variable, and then that variable is inspected further.
I've been having a bit of problems trying to figure out why my encryption is different in go compared to php and node. I was hoping someone could help me figure out the differences. Let's assume this is the data:
plaintext: hello big worldshello big worlds
key: jJr44P3WSM5F8AC573racFpzU5zj7Rg5
iv: 97iEhhtgVjoVwdUw
Here are the resulting encryptions in base64:
Node and PHP return :
OTdpRWhodGdWam9Wd2RVd0OgJ+Z7pSCVioYq41721jarxqLKXN3PcnnY6/AOrHeEfsTxXfCgm2uUi+vmCAdpvw==
Go returns:
OTdpRWhodGdWam9Wd2RVd0OgJ+Z7pSCVioYq41721jarxqLKXN3PcnnY6/AOrHeE
As you can see they're almost identical and its been driving me crazy. Could you guys take quick look at the encryption code below and give me hints on what the problem could be?
GO:
func EncryptString(plainstring string, keystring string, encFormat int, ivOverride bool) (string) {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key := []byte(keystring)
plaintext := []byte(plainstring)
// CBC mode works on blocks so plaintexts may need to be padded to the
// next whole block. For an example of such padding, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
// assume that the plaintext is already of the correct length.
if len(plaintext)%aes.BlockSize != 0 {
panic("plaintext is not a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(bytes.NewReader([]byte("97iEhhtgVjoVwdUw")), iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
return base64.StdEncoding.EncodeToString(ciphertext)
}
NODE:
encryptString: function(string, key, fmt = null, ivOverride = false) {
// Build an initialisation vector
let iv;
if(!ivOverride) {
iv = crypto.randomBytes(IV_NUM_BYTES).toString('hex').slice(0,16);
} else {
iv = IV_OVERRIDE_VALUE; //97iEhhtgVjoVwdUw
}
// and encrypt
let encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let encryptedData = encryptor.update(string, 'utf8', 'binary') + encryptor.final('binary');
encryptedData = iv+''+encryptedData;
encryptedData = Buffer.from(encryptedData, 'binary').toString('base64');
return encryptedData;
}
I've noticed that removing encryptor.final('binary') makes the two result in the same encryption but php does not have the .final() thing going for it. Php uses open_ssl_encrypt() which seems to have this built in. Is there a way to add an equivalent in go? Looking for advice. Thanks
Okay, I managed to get the go output to match your other outputs, but I'm not 100% clear on all of the details--in particular why the PHP and Node versions behave the way they do (your output from the Go version seems like the "correct" result in my mind, as I'll explain).
My first observation was that your output from Node and PHP was longer than the Go version, by approximately one block length, and only the tail end is different. This told me that, somehow, those versions are being padded more than the go version.
So, I tried padding the Go version according to the default padding scheme used by PHP and Node, PKCS#7. Basically, if you need to pad by 5 bytes, then each of the padding bytes should be equal to 0x05, 6 bytes are padded with 0x06, etc. Go's default aes.BlockSize is equal to 16, so I tried padding your input string with 16 0x10 bytes. This led to the correct answer!
Honestly, not padding the input at all if it's already block-aligned is understandable behavior, but apparently Node and PHP follow RFC 5652 and always add padding (see the edit), even if they need to add another entire block just of padding.
Here's the Go code to make your outputs match:
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
"io"
)
// Based on Wikipedia: https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7
func PadToBlockSize(input string) string {
paddingNeeded := aes.BlockSize - (len(input) % aes.BlockSize)
if paddingNeeded >= 256 {
panic("I'm too lazy to handle this case for the sake of an example :)")
}
if paddingNeeded == 0 {
paddingNeeded = aes.BlockSize
}
// Inefficient, once again, this is an example only!
for i := 0; i < paddingNeeded; i++ {
input += string(byte(paddingNeeded))
}
return input
}
// (Identical to your code, I just deleted comments to save space)
func EncryptString(plainstring string, keystring string, encFormat int, ivOverride bool) string {
key := []byte(keystring)
plaintext := []byte(plainstring)
if len(plaintext)%aes.BlockSize != 0 {
panic("plaintext is not a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(bytes.NewReader([]byte("97iEhhtgVjoVwdUw")), iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
return base64.StdEncoding.EncodeToString(ciphertext)
}
func main() {
plaintext := "hello big worldshello big worlds"
key := "jJr44P3WSM5F8AC573racFpzU5zj7Rg5"
phpText := "OTdpRWhodGdWam9Wd2RVd0OgJ+Z7pSCVioYq41721jarxqLKXN3PcnnY6/AOrHeEfsTxXfCgm2uUi+vmCAdpvw=="
fmt.Println("Go : " + EncryptString(PadToBlockSize(plaintext), key, 0, false))
fmt.Println("PHP: " + phpText)
}
Edit:
Actually, it looks like Node and PHP are just following RFC 5652 correctly, which mandates that all input needs to be padded. The fact that padding will always be present, even if the input was block-aligned, disambiguates decryption. Go just leaves the padding step to the user.
I need to get values from a serialized string which generated from php code
So I use a package named:php_serialize to unserialize the string and then got a result of interface{} type .
But I have no idea how to get values inside the result.
This is code:
package main
import (
"github.com/yvasiyarov/php_session_decoder/php_serialize"
"fmt"
)
func main() {
// this string is generated from php code
str := `a:3:{s:4:"name";s:3:"tom";s:3:"age";s:2:"23";s:7:"friends";a:2:{i:0;a:1:{s:4:"name";s:5:"jerry";}i:1;a:1:{s:4:"name";s:4:"jack";}}}`
decoder := php_serialize.NewUnSerializer(str)
if result, err := decoder.Decode(); err != nil {
panic(err)
} else {
fmt.Println(result)
}
}
The print result is :
map[name:tom age:23 friends:map[0:map[name:jerry] 1:map[name:jack]]]
This result is a php_serialize.PhpValue type, which is interface{} type
The next step is how to get values inside the result?
such as get the age field and value
You must assert the result to map[string]interface:
mResult := result.(map[string]interface{})
fmt.Println(mResult["name"])
And once more assertion for friends:
mFriends := mResult["friends"].(map[int]map[string]interface{})
Then use it: mFriends[0]["name"]
Here some ways to access the data:
package main
import (
"fmt"
"github.com/yvasiyarov/php_session_decoder/php_serialize"
)
func main() {
// this string is generated from php code
str := `a:3:{s:4:"name";s:3:"tom";s:3:"age";s:2:"23";s:7:"friends";a:2:{i:0;a:1:{s:4:"name";s:5:"jerry";}i:1;a:1:{s:4:"name";s:4:"jack";}}}`
decoder := php_serialize.NewUnSerializer(str)
result, err := decoder.Decode()
if err != nil {
panic(err)
}
fmt.Println(result)
// simple assert
t := result.(php_serialize.PhpArray)
// use php_seriale build in function to get string
strVal := php_serialize.PhpValueString(t["name"])
fmt.Println(strVal)
// type switch in case of different valid types
switch t := result.(type) {
default:
fmt.Printf("unexpected type %T\n", t) // %T prints whatever type t has
case php_serialize.PhpArray:
fmt.Println(t)
fmt.Println(t["name"])
fmt.Println(t["age"])
// should be done recursively...
switch f := t["friends"].(type) {
default:
fmt.Printf("unexpected type %T\n", f) // %T prints whatever type t has
case php_serialize.PhpArray:
fmt.Println(f)
fmt.Println(f[0])
fmt.Println(f[1])
}
}
}
I hope this gives you some ideas.
Basic concept
php_serialize has built in functions to convert primitives.
Variable structures are represented with built in types which need to be used to access the structure.
I want to crypt privateKey & publicKey to sha1 in base64 with Swift, but the output is not the one I see in PHP urlencode base64_encode which I tried in Codecademy:"https://www.codecademy.com/courses/web-beginner-en-StaFQ/0/3?curriculum_id=5124ef4c78d510dd89003eb8".
Pls see the following codes in Swift and Codecademy:
Swift:
//pls see func dataFromHexadecimalString() details here "http://stackoverflow.com/questions/26501276/convert-string-to-hex-string-in-swift/26502285#26502285"
extension String {
func dataFromHexadecimalString() -> NSData? {
let trimmedString = self.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "<> ")).stringByReplacingOccurrencesOfString(" ", withString: "")
var error: NSError?
let regex = NSRegularExpression(pattern: "^[0-9a-f]*$", options: .CaseInsensitive, error: &error)
let found = regex?.firstMatchInString(trimmedString, options: nil, range: NSMakeRange(0, count(trimmedString)))
if found == nil || found?.range.location == NSNotFound || count(trimmedString) % 2 != 0 {
return nil
}
let data = NSMutableData(capacity: count(trimmedString) / 2)
for var index = trimmedString.startIndex; index < trimmedString.endIndex; index = index.successor().successor() {
let byteString = trimmedString.substringWithRange(Range<String.Index>(start: index, end: index.successor().successor()))
let num = UInt8(byteString.withCString { strtoul($0, nil, 16) })
data?.appendBytes([num] as [UInt8], length: 1)
}
return data
}
}
func URLEcodekey() -> String {
let appid="a1b2c34d5e"
let privateKey="ef7d6s0d"
let areaid="101020900"
let time="201507191254"
let publicKey="http://open.weather.com.cn/data/?areaid=\(areaid)&type=forecast_v&date=\(time)&appid=\(appid)"
let cPrivateKey=privateKey.dataUsingEncoding(NSUTF8StringEncoding)!
let cPublicKey=publicKey.dataUsingEncoding(NSUTF8StringEncoding)!
var cHMAC = [CUnsignedChar](count: Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), cPublicKey.bytes, Int(cPublicKey.length), cPrivateKey.bytes, Int(cPrivateKey.length), &cHMAC)
let hexKeyString=NSMutableString(capacity: Int(CC_SHA1_DIGEST_LENGTH))
for byte in cHMAC{
hexKeyString.appendFormat("%02hhx", byte)
}
println("hexKeyString:\(encryptedKey)")
let binaryData = hexKeyString.dataFromHexadecimalString()
let base64String = binaryData?.base64EncodedStringWithOptions(nil)
println("base64String:\(base64String)")
var urlEncodeKey=base64String!.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())!
println("urlEncodeKey:\(urlEncodeKey)")
return urlEncodeMessage
}
the outputs are:
hexKeyString:d4433d42b1505c00a4aa80205171d0d04754d254
base64String:1EM9QrFQXACkqoAgUXHQ0EdU0lQ=
urlEncodeKey:1EM9QrFQXACkqoAgUXHQ0EdU0lQ=
PHP in Codecademy:
echo urlencode(base64_encode(hash_hmac('sha1', " http://open.weather.com.cn/data/?areaid=101020900&type=forecast_v&date=201507191254&appid=a1b2c34d5e", "ef7d6s0d", TRUE)));
the output is:
A5O59Y%2BFbGjhVwaI9JNB7DkcX%2F4%3D // the output is much like the
example in API, which I think maybe the right one.
So, how can I receive the right urlEncodeKey for my privateKey & publicKey like in PHP?
Thank you very much in advance!
You should read more about cryptography and hashing. In your case, there's no public key, private key, ... SHA stands for Secure hash algorithm and what you're trying to get is Hash based authentication code. Check Wikipedia articles about HMAC, SHA-1, Public key, ... I strongly recommend to read more about it otherwise you can create more damage if you misunderstand it.
Back to your problem. It's in one character:
Swift code - let publicKey="http://open.weather.com.cn...
PHP code - hash_hmac('sha1', " http://open.weather.com.cn...
Do you see where the problem is? In your PHP code, there's one space character just before http. This character is not in your Swift code.
Honestly, I didn't check your whole code, because I don't know why you're trying to convert it from hexadecimal string, etc. Used some parts only and rewrote it from scratch for you. Here's working example:
func URLEncodedKey() -> String? {
let appid = "a1b2c34d5e"
let time = "201507191254"
let areaid = "101020900"
let key = "ef7d6s0d"
let string = " http://open.weather.com.cn/data/?areaid=\(areaid)&type=forecast_v&date=\(time)&appid=\(appid)"
// ^ <- in your PHP example, there's space
guard let keyData = key.dataUsingEncoding(NSUTF8StringEncoding),
stringData = string.dataUsingEncoding(NSUTF8StringEncoding),
outputData = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH)) else {
return nil
}
outputData.length = Int(CC_SHA1_DIGEST_LENGTH)
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1),
keyData.bytes, keyData.length,
stringData.bytes, stringData.length,
outputData.mutableBytes)
return outputData
.base64EncodedStringWithOptions([])
.stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet())
}
Return value is:
`Optional("A5O59Y+FbGjhVwaI9JNB7DkcX/4=")`
Which is what you get when you decode your PHP output.
Just replace URLQueryAllowedCharacterSet with any of the following character sets:
class func URLUserAllowedCharacterSet() -> NSCharacterSet
class func URLPasswordAllowedCharacterSet() -> NSCharacterSet
class func URLHostAllowedCharacterSet() -> NSCharacterSet
class func URLPathAllowedCharacterSet() -> NSCharacterSet
class func URLQueryAllowedCharacterSet() -> NSCharacterSet
class func URLFragmentAllowedCharacterSet() -> NSCharacterSet
Depends on your use case. IOW in which part of the URL your would like to use it.
I was hoping someone had already implemented this in golang as I am far from even good at cryptography. However in porting a project from php to golang I have run into an issue with porting the openssl_encrypt method found here. I have also dug into the source code a little with no avail.
Here is the method I have implemented in golang. which gives me the output
lvb7JwaI4OCYUrdJMm8Q9uDd9rIILnvbZKJb/ozFbwCmLKkxoJN5Zf/ODOJ/RGq5
Here is the output I need when using php.
lvb7JwaI4OCYUrdJMm8Q9uDd9rIILnvbZKJb/ozFbwDV98XaJjvzEjBQp7jc+2DH
And here is the function I used to generate it with php.
$data = "This is some text I want to encrypt";
$method = "aes-256-cbc";
$password = "This is a really long key and su";
$options = 0;
$iv = "MMMMMMMMMMMMMMMM";
echo openssl_encrypt($data, $method, $password, $options, $iv);
To me it looks like it is very close and I must be missing something obvious.
You were very close, but you had the padding wrong. According to this answer (and the PHP docs), PHP uses the default OpenSSL padding behavior, which is to use the required number of padding bytes as the padding byte value.
The only change I made was:
copy(plaintextblock[length:], bytes.Repeat([]byte{uint8(extendBlock)}, extendBlock))
You can see the full updated code here.
Others beat me to the answer while I was playing with it, but I have a "better" fixed version of your example code that also takes into account that padding is always required (at least to emulate what the php code does).
It also shows the openssl command line that you'd use to do the same thing, and if available runs it (of course the playground won't).
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
"log"
"os/exec"
"strings"
)
func main() {
const input = "This is some text I want to encrypt"
fmt.Println(opensslCommand(input))
fmt.Println(aesCBCenctypt(input))
}
func aesCBCenctypt(input string) string {
// Of course real IVs should be from crypto/rand
iv := []byte("MMMMMMMMMMMMMMMM")
// And real keys should be from something like PBKDF2, RFC 2898.
// E.g. use golang.org/x/crypto/pbkdf2 to turn a
// "passphrase" into a key.
key := []byte("This is a really long key and su")
// Make sure the block size is a multiple of aes.BlockSize
// Pad to aes.BlockSize using the pad length as the padding
// byte. If we would otherwise need no padding we instead
// pad an entire extra block.
pad := (aes.BlockSize - len(input)%aes.BlockSize)
if pad == 0 {
pad = aes.BlockSize
}
data := make([]byte, len(input)+pad)
copy(data, input)
for i := len(input); i < len(input)+pad; i++ {
data[i] = byte(pad)
}
cb, err := aes.NewCipher(key)
if err != nil {
log.Fatalln("error NewCipher():", err)
}
mode := cipher.NewCBCEncrypter(cb, iv)
mode.CryptBlocks(data, data)
return base64.StdEncoding.EncodeToString(data)
}
// Just for comparison, don't do this for real!
func opensslCommand(input string) string {
iv := []byte("MMMMMMMMMMMMMMMM")
key := []byte("This is a really long key and su")
args := []string{"enc", "-aes-256-cbc", "-base64"}
// "-nosalt", "-nopad"
args = append(args, "-iv", fmt.Sprintf("%X", iv))
args = append(args, "-K", fmt.Sprintf("%X", key))
cmd := exec.Command("openssl", args...)
// Show how you could do this via the command line:
fmt.Println("Command:", strings.Join(cmd.Args, " "))
cmd.Stdin = strings.NewReader(input)
result, err := cmd.CombinedOutput()
if err != nil {
if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound {
// openssl not available
return err.Error() // XXX
}
// some other error, show it and the (error?) output and die
fmt.Println("cmd error:", err)
log.Fatalf("result %q", result)
}
// Strip trailing '\n' and return it.
if n := len(result) - 1; result[n] == '\n' {
result = result[:n]
}
return string(result)
}
Playground