github.com/tommi2day/gomodules@v1.13.2-0.20240423190010-b7d55d252a27/pwlib/openssl_test.go (about)

     1  package pwlib
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"encoding/base64"
     7  	"fmt"
     8  	"os"
     9  	"os/exec"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/tommi2day/gomodules/common"
    14  
    15  	"github.com/tommi2day/gomodules/test"
    16  
    17  	openssl "github.com/Luzifer/go-openssl/v4"
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  const (
    23  	plaintext = "hallowelt"
    24  	//nolint gosec
    25  	passphrase = "z4yH36a6zerhfE5427ZV"
    26  	plainfile  = `
    27  # Testfile
    28  !default:defuser2:failure
    29  !default:testuser:default
    30  test:testuser:testpass
    31  testdp:testuser:xxx:yyy
    32  !default:defuser2:default
    33  !default:testuser:failure
    34  !default:defuser:default
    35  `
    36  )
    37  
    38  // var digest = openssl.BytesToKeySHA256
    39  
    40  func TestEncryptToDecrypt(t *testing.T) {
    41  	o := openssl.New()
    42  	enc, err := o.EncryptBytes(passphrase, []byte(plaintext), SSLDigest)
    43  	if err != nil {
    44  		t.Fatalf("Test errored at encrypt: %s", err)
    45  	}
    46  
    47  	dec, err := o.DecryptBytes(passphrase, enc, SSLDigest)
    48  	if err != nil {
    49  		t.Fatalf("Test errored at decrypt: %s", err)
    50  	}
    51  
    52  	if string(dec) != plaintext {
    53  		t.Errorf("Decrypted text did not match input.")
    54  	}
    55  }
    56  
    57  func TestPublicEncryptString(t *testing.T) {
    58  	app := "test_encrypt_String"
    59  	testdata := test.TestData
    60  	pc := NewConfig(app, testdata, testdata, "Test", typeGO)
    61  
    62  	err := os.Chdir(test.TestDir)
    63  	require.NoErrorf(t, err, "ChDir failed")
    64  	_, _, err = GenRsaKey(pc.PubKeyFile, pc.PrivateKeyFile, pc.KeyPass)
    65  	require.NoErrorf(t, err, "Prepare Key failed:%s", err)
    66  
    67  	crypted, err := PublicEncryptString(plaintext, pc.PubKeyFile)
    68  	// run
    69  	t.Run("default Encrypt String", func(t *testing.T) {
    70  		assert.NoErrorf(t, err, "Encryption failed: %s", err)
    71  		assert.NotEmpty(t, crypted, "Crypted String empty")
    72  	})
    73  
    74  	t.Run("default Decrypt String", func(t *testing.T) {
    75  		actual, err := PrivateDecryptString(crypted, pc.PrivateKeyFile, pc.KeyPass)
    76  		expected := plaintext
    77  		assert.NoErrorf(t, err, "Decryption failed: %s", err)
    78  		assert.NotEmpty(t, actual)
    79  		assert.Equalf(t, expected, actual, "Data Mismatch exp:%s,act:%s", expected, actual)
    80  	})
    81  }
    82  
    83  func TestOpensslCompString(t *testing.T) {
    84  	// echo -n "$plain"|openssl rsautl -encrypt -pkcs -inkey $PUBLICKEYFILE -pubin |base64
    85  	// echo -n "$CRYPTED"|base64 -d   |openssl rsautl -decrypt -inkey ${PRIVATEKEYFILE} -passin pass:$KEYPASS
    86  
    87  	var cmdout bytes.Buffer
    88  	var cmderr bytes.Buffer
    89  	test.Testinit(t)
    90  	app := "test_openssl_string"
    91  	testdata := test.TestData
    92  
    93  	// set env
    94  	pc := NewConfig(app, testdata, testdata, "Test", typeOpenssl)
    95  	err := os.Chdir(test.TestDir)
    96  	require.NoErrorf(t, err, "ChDir failed")
    97  
    98  	// prepare keys
    99  	_, _, err = GenRsaKey(pc.PubKeyFile, pc.PrivateKeyFile, pc.KeyPass)
   100  	require.NoErrorf(t, err, "Prepare Key failed:%s", err)
   101  	t.Run("Encrypt_Openssl-Decrypt_String", func(t *testing.T) {
   102  		// encrypt using openssl os cmd
   103  		cmdArgs := []string{
   104  			"openssl", "rsautl",
   105  			"-inkey", pc.PubKeyFile,
   106  			"-pubin",
   107  			"-pkcs",
   108  			"-encrypt",
   109  		}
   110  		// nolint gosec
   111  		cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
   112  		t.Logf("CMD: %v", cmdArgs)
   113  		cmdout.Reset()
   114  		cmderr.Reset()
   115  		cmd.Stdout = &cmdout
   116  		cmd.Stderr = &cmderr
   117  		cmd.Stdin = strings.NewReader(plaintext)
   118  		if err := cmd.Run(); err != nil {
   119  			t.Fatalf("Running openssl CLI failed: %v (%s)", err, cmderr.String())
   120  		}
   121  		// encode base64
   122  		crypted := base64.StdEncoding.EncodeToString(cmdout.Bytes())
   123  
   124  		// decode openssl encoded string with go functions
   125  		actual, err := PrivateDecryptString(crypted, pc.PrivateKeyFile, pc.KeyPass)
   126  		if err != nil {
   127  			t.Fatalf("Decryprion failed: %v", err)
   128  		}
   129  		// compare
   130  		expected := plaintext
   131  		assert.NotEmpty(t, actual)
   132  		assert.Equalf(t, expected, actual, "Data Mismatch exp:%s,act:%s", expected, actual)
   133  	})
   134  
   135  	t.Run("Encrypt_String-OpenSSL_decrypt", func(t *testing.T) {
   136  		// encode string with go functions
   137  		crypted, err := PublicEncryptString(plaintext, pc.PubKeyFile)
   138  		if err != nil {
   139  			t.Fatalf("Encryprion failed: %v", err)
   140  		}
   141  		t.Logf("B64: %s", crypted)
   142  		// revert base64 encoding
   143  		b64dec, err := base64.StdEncoding.DecodeString(crypted)
   144  		if err != nil {
   145  			t.Fatalf("decode base64 failed: %v", err)
   146  		}
   147  
   148  		// decode crypted string in bin format using openssl os cmd
   149  		cmdArgs := []string{
   150  			"openssl", "rsautl",
   151  			"-inkey", pc.PrivateKeyFile,
   152  			"-pkcs",
   153  			"-decrypt",
   154  			"-passin", fmt.Sprintf("pass:%s", pc.KeyPass),
   155  		}
   156  		// nolint gosec
   157  		cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
   158  		t.Logf("CMD: %v", cmdArgs)
   159  		cmdout.Reset()
   160  		cmderr.Reset()
   161  		cmd.Stdout = &cmdout
   162  		cmd.Stderr = &cmderr
   163  		cmd.Stdin = bytes.NewReader(b64dec)
   164  		expected := plaintext
   165  		if err := cmd.Run(); err != nil {
   166  			t.Fatalf("Running openssl CLI failed: %v (%s)", err, cmderr.String())
   167  		}
   168  		actual := cmdout.String()
   169  		// compare
   170  		assert.NotEmpty(t, actual)
   171  		assert.Equalf(t, expected, actual, "Data Mismatch exp:%s,act:%s", expected, actual)
   172  	})
   173  }
   174  
   175  func TestOpensslFile(t *testing.T) {
   176  	var cmdout bytes.Buffer
   177  	var cmderr bytes.Buffer
   178  	test.Testinit(t)
   179  	app := "test_openssl_file"
   180  	testdata := test.TestDir + "/testdata"
   181  	// set env
   182  	pc := NewConfig(app, testdata, testdata, app, typeOpenssl)
   183  	err := os.Chdir(test.TestDir)
   184  	require.NoErrorf(t, err, "ChDir failed")
   185  	filename := pc.PlainTextFile
   186  	_ = os.Remove(filename)
   187  	//nolint gosec
   188  	err = os.WriteFile(filename, []byte(plainfile), 0644)
   189  	require.NoErrorf(t, err, "Create testdata failed")
   190  
   191  	// prepare keys
   192  	_, _, err = GenRsaKey(pc.PubKeyFile, pc.PrivateKeyFile, pc.KeyPass)
   193  	require.NoErrorf(t, err, "Prepare Key failed:%s", err)
   194  	// run
   195  	t.Run("default Encrypt File", func(t *testing.T) {
   196  		err := PubEncryptFileSSL(pc.PlainTextFile, pc.CryptedFile, pc.PubKeyFile, pc.SessionPassFile)
   197  		assert.NoErrorf(t, err, "Encryption failed: %s", err)
   198  		assert.FileExists(t, pc.CryptedFile)
   199  	})
   200  	t.Run("default Decrypt File", func(t *testing.T) {
   201  		plaintxt, err := common.ReadFileToString(pc.PlainTextFile)
   202  		require.NoErrorf(t, err, "PlainTextfile %s not readable:%s", err)
   203  		expected := len(plaintxt)
   204  		content, err := PrivateDecryptFileSSL(pc.CryptedFile, pc.PrivateKeyFile, pc.KeyPass, pc.SessionPassFile)
   205  		assert.NoErrorf(t, err, "Decryption failed: %s", err)
   206  		assert.NotEmpty(t, content)
   207  		actual := len(content)
   208  		assert.Equalf(t, expected, actual, "Lines misamtch exp:%d,act:%d", expected, actual)
   209  	})
   210  	t.Run("Encrypt_Openssl-Decrypt_Api", func(t *testing.T) {
   211  		const rb = 16
   212  		var actual, crypted string
   213  		// create session key
   214  		random := make([]byte, rb)
   215  		_, err = rand.Read(random)
   216  		if err != nil {
   217  			t.Fatalf("Cannot generate session key:%s", err)
   218  		}
   219  		sessionKey := base64.StdEncoding.EncodeToString(random)
   220  		t.Logf("Create Random SessionKeyin  %s: %s", pc.SessionPassFile, sessionKey)
   221  
   222  		// encrypt session key and save to file
   223  		// echo -n sessionKey |openssl rsautl -encrypt -pkcs -inkey PubKeyFile -pubin |openssl enc -base64 -out SessionPassFile
   224  		crypted, err = PublicEncryptString(sessionKey, pc.PubKeyFile)
   225  		if err != nil {
   226  			t.Fatalf("Encrypting Keyfile failed: %v", err)
   227  		}
   228  		//nolint gosec
   229  		err = os.WriteFile(pc.SessionPassFile, []byte(crypted), 0644)
   230  		if err != nil {
   231  			t.Fatalf("Cannot write session Key file %s:%v", pc.SessionPassFile, err)
   232  		}
   233  
   234  		// encrypt using openssl cmd
   235  		cmdArgs := []string{
   236  			"openssl", "enc", "-e",
   237  			"-aes-256-cbc",
   238  			"-base64",
   239  			"-pass", fmt.Sprintf("pass:%s", sessionKey),
   240  			"-md", "sha256",
   241  			"-in", pc.PlainTextFile,
   242  			"-out", pc.CryptedFile,
   243  		}
   244  		// nolint gosec
   245  		cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
   246  		t.Logf("CMD: %v", cmdArgs)
   247  		cmdout.Reset()
   248  		cmderr.Reset()
   249  		cmd.Stdout = &cmdout
   250  		cmd.Stderr = &cmderr
   251  		if err = cmd.Run(); err != nil {
   252  			t.Fatalf("Running openssl CLI failed: %v (%s)", err, cmderr.String())
   253  		}
   254  
   255  		// decrypt openssl encoded data using API
   256  		actual, err = PrivateDecryptFileSSL(pc.CryptedFile, pc.PrivateKeyFile, pc.KeyPass, pc.SessionPassFile)
   257  
   258  		// compare
   259  		expected := plainfile
   260  		assert.NotEmpty(t, actual)
   261  		assert.Equalf(t, expected, actual, "Data Mismatch exp:%s,act:%s", expected, actual)
   262  	})
   263  	t.Run("Encrypt_API-Decrypt_openssl", func(t *testing.T) {
   264  		// encrypt using api
   265  		err := PubEncryptFileSSL(pc.PlainTextFile, pc.CryptedFile, pc.PubKeyFile, pc.SessionPassFile)
   266  		assert.NoErrorf(t, err, "Cannot Encrypt using API:%s", err)
   267  		if err != nil {
   268  			t.Fatalf("Cannot Encrypt using API:%s", err)
   269  		}
   270  
   271  		// verify witch openssl cmd
   272  		// read session pass file
   273  		//nolint gosec
   274  		data, err := os.ReadFile(pc.SessionPassFile)
   275  		if err != nil {
   276  			t.Fatalf("Cannot Read SessionPassFile %s:%v", pc.SessionPassFile, err)
   277  		}
   278  		cryptedKey := string(data)
   279  		// revert base64 encoding
   280  		b64dec, err := base64.StdEncoding.DecodeString(cryptedKey)
   281  		if err != nil {
   282  			t.Fatalf("decode base64 failed: %v", err)
   283  		}
   284  
   285  		// decode crypted string in bin format using openssl os cmd
   286  		cmdArgs := []string{
   287  			"openssl", "rsautl",
   288  			"-inkey", pc.PrivateKeyFile,
   289  			"-pkcs",
   290  			"-decrypt",
   291  			"-passin", fmt.Sprintf("pass:%s", pc.KeyPass),
   292  		}
   293  		// nolint gosec
   294  		cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
   295  		t.Logf("CMD: %v", cmdArgs)
   296  		cmdout.Reset()
   297  		cmderr.Reset()
   298  		cmd.Stdout = &cmdout
   299  		cmd.Stderr = &cmderr
   300  		cmd.Stdin = bytes.NewReader(b64dec)
   301  		if err := cmd.Run(); err != nil {
   302  			t.Fatalf("Running openssl CLI failed: %v (%s)", err, cmderr.String())
   303  		}
   304  		sessionKey := cmdout.String()
   305  		t.Logf("SessionKey: %s", sessionKey)
   306  
   307  		// decrypt using openssl cmd, must use -base64 -A for singleline base64 string
   308  		cmdArgs = []string{
   309  			"openssl", "enc", "-d",
   310  			"-aes-256-cbc",
   311  			"-base64",
   312  			"-A",
   313  			"-pass", fmt.Sprintf("pass:%s", sessionKey),
   314  			"-md", "sha256",
   315  			"-in", pc.CryptedFile,
   316  		}
   317  		// nolint gosec
   318  		cmd = exec.Command(cmdArgs[0], cmdArgs[1:]...)
   319  		t.Logf("CMD: %v", cmdArgs)
   320  		cmdout.Reset()
   321  		cmderr.Reset()
   322  		cmd.Stdout = &cmdout
   323  		cmd.Stderr = &cmderr
   324  		if err := cmd.Run(); err != nil {
   325  			t.Fatalf("Running openssl CLI failed: %v (%s)", err, cmderr.String())
   326  		}
   327  
   328  		actual := cmdout.String()
   329  		// compare
   330  		expected := plainfile
   331  		assert.NotEmpty(t, actual)
   332  		assert.Equalf(t, expected, actual, "Data Mismatch exp:%s,act:%s", expected, actual)
   333  	})
   334  }