2


how can I mask the middle lines of a PEM key in bash script

I need to echo my pem key with mask(*) the middle lines through a bash script

for example:-

-----BEGIN CERTIFICATE-----
MIICyjCCAbICCQDrpZYh8et7yTANBgkqhkiG9w0BAQsFADAnMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMB4XDTE4MTExMjIwNDEwNVoXDTE4
MTIxMjIwNDEwNVowJzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
DAJTRjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnIdgpml8+xk+Oj
1RGMCyJ1P15RiM6rdtszT+DFBg893Lqsjoyd5YgwELLz0Ux8nviG4L5OXOujEpAP
2cQBxTSLQjBELBZY9q0Qky3+2ewqV6lSfcXrcf/JuDJGR5K8HSqwNG35R3WGnZ+O
JhY0Dmx06IAs/FF8gP88zTQ8M7zuaThkF8MaF4sWPf6+texQwjzk4rewknGBFzar
9wFxVwNCyDD6ewIYPtgDxdJ1bwBVoX3KKKXm8GStl/Zva0aEtbSq/161J4VbTro2
dxArMPKzxjD6NLyF59UNs7vbzyfiw/Wq7BJzU7Kued5KdGt0bEiyWZYO+EvvxGmE
1pHfqysCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAavj4CA+7XFVHbwYMbK3c9tN/
73hkMvkAZWix5bfmOo0cNRuCeJnRIX+o6DmusIc8eXJJJV/20+zoSvUwlsLDPXoN
+c41GfIiEUSaSdSBtETMy8oPga718nIwAvNgYiUHXnV3B0nLYBUpYSnsD00/6VXG
xZUIEVBd7Ib5aRwmK8U5drxoWaBoG5qdvH9iapwTrCcPsRjsLBq7Iza2oBORGlfF
CjqiW2+KJzwRiTQj70yceniGVHM+VSpFYCLJ0mXeyLfITy7joqxr4AGYz+EhpLuf
iDpYDNYlr0JDVQqogskWjrnWOh0YcIJKgVtiTh2HDM5TdQgeXg4wv5IqLok0Tw==
-----END CERTIFICATE-----

as

-----BEGIN CERTIFICATE-----
MIICyjCCAbICCQDrpZYh8et7yTANBgkqhkiG9w0BAQsFADAnMQswCQYDVQQGEwJV
****************************************************************
iDpYDNYlr0JDVQqogskWjrnWOh0YcIJKgVtiTh2HDM5TdQgeXg4wv5IqLok0Tw==
-----END CERTIFICATE-----

I tried with awk but it failed:

awk 'BEGIN{FS=OFS=""} {for(i=2;i<='15';i++) $i="*"}1'
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Pradeep Chandran
  • 327
  • 5
  • 11
  • 3
    What have you searched for, and what did you find? What have you tried, and how did it fail? – tripleee Nov 27 '19 at 08:53
  • tried with awk but its failed ```awk 'BEGIN{FS=OFS=""} {for(i=2;i<='15';i++) $i="*"}1'``` – Pradeep Chandran Nov 27 '19 at 08:57
  • You can't use single quotes inside single quotes. The number should not be quoted at all anyway. – tripleee Nov 27 '19 at 09:06
  • But perhaps a better fix would be `'NR>2 && NR < 16 { gsub(/./, "*") } 1'` if you know the exact number of lines. To only print the first masked line, replace `1` with `NR<=3 || NR >= 15` for example. To cope with a variable number of lines, keep the last few lines in memory and print in the `END` block. – tripleee Nov 27 '19 at 09:09
  • @PradeepChandran, How many lines you want to mask? All apart from 1st and last? Can you please confirm once? – RavinderSingh13 Nov 27 '19 at 09:16
  • Please update the question with real requirements. Your attempt implied you only need a solution for a 17-line file. – Wiktor Stribiżew Nov 27 '19 at 10:05

4 Answers4

2

Scenario 1: 17-line PEM file

It looks like your file has a fixed amount of lines and you want to replace all lines from the third till the fifteenth one.

You may solve it with sed:

sed -e '3,15d' pemfile | sed -e  "3 i\\$(printf '*%.0s' {1..64})" > newpemfile

NOTES:

  • sed -e '3,15d' pemfile - removes lines from the third through the fifteenth
  • sed -e "3 i\\$(printf '*%.0s' {1..64})" > newpemfile - adds a 64-asterisk line as the third line and saves the file as newpemfile.

Scenario 2: Replace all lines but the first/last between two delimiter lines with a line with hardcoded number of asterisks

If your problem is replacing the lines between two delimiters you may use GNU sed solution like

sed -E "/^-+BEGIN CERTIFICATE-+$/{
    n;n;
    :a; N; /\n-+END CERTIFICATE-+$/!ba; s/.*(\n.*\n)/$(printf '*%.0s' {1..64})\1/;
}" pemfile

See this online sed demo

Here,

  • /^-+BEGIN CERTIFICATE-+$/{ - matches a line like ---BEGIN CERTIFICATE---- and if found, the block commands are executed:
    • n;n; - read two lines, the last is in the pattern space
    • :a; N; /\n-+END CERTIFICATE-+$/!ba; - read all lines up to a line like ---END CERTIFICATE--- appending with newlines to the pattern space
    • s/.*(\n.*\n)/$(printf '*%.0s' {1..64})\1/; - replace the whole pattern space text with 64 asterisks and the last two lines (we remove all lines up to the last two here) }`
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
2

This might work for you (GNU sed):

sed -n '1p;1n;2p;2s/./*/gp;$!N;$!D;p' file

Turn off implicit printing by using the -n option.

Print the first and second lines, then replace every character of the second line by *'s and print that too.

Make a window of two lines throughout the remainder of the file and print it on the last line.

On reflection, a shorter solution:

sed 'N;2p;4s/\S/*/g;4P;$!D' file

does the same as the first solution but perhaps more cryptically.

potong
  • 55,640
  • 6
  • 51
  • 83
  • it works with most of the pem keys but not working with single lined pem keys like ```ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAhs3/WTw+nYEXM9daoBUA9Z76tjJ1qXRVUEyc/XjxY7A4xnSd+IQeU9PItu2pu/jIeXUM1ksLdCoTPdqDTgrojQqjRNMjKrjDgp4BHSR5t0z2IYFbnkOmlp4t6CJ2XjfMMeBKnGa+tHpcZ+THJIVOK+KjdBEcwgoU3D7V++XDRrb9GvTMQTnwM0WPkHFqPyJfRaEyl89RVRhlQtseI08uCRRwZnxIzWeghoGGc0vfjvyFJud4YfEjP0wvd07XGPBg/ubJNdoPNS/73XdrS935vsBGZy20AjsHOjs7ZErqA46Ija2TWQXS7UUOLaSukYRNqFzh5A40ePuVAkuflnS+XAgtw== test``` – Pradeep Chandran Nov 27 '19 at 09:57
  • fixed that issue, split the single line to multiple with fold command thanks for the help!!!! – Pradeep Chandran Nov 27 '19 at 10:07
0

I highly suggest using @WiktorStribizew's anser if the file is actually a fixed 16 lines long.

If it can vary (keys might have more or less bits), the simple way is to combine head and tail:

head -n2 key.pem ; echo 'XXXXXXX' ; tail -n2 key.pem

But if you're looking for a single command, take a look at this answer form a different question: https://stackoverflow.com/a/48002163/2284641

Johannes H.
  • 5,875
  • 1
  • 20
  • 40
0

Here is what I did find work on our pem files

awk '/-----BEGIN/ {f=2} f-->0; /-----END/' etc/auth/server.pem
-----BEGIN CERTIFICATE-----
MIID8jCCAhoCCQDGQsEmfeBvJTANBgkqhkiG6w0BAQsFADB/MQswCQYDVQQGEwJV
-----END CERTIFICATE-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIF8jBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG6w0BBQwwDgQIpS+A9Ql+5uUCAggA
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MII8ejCCAmICCQCNHBN8tj/FwzANBgkqhkiG6w0BAQsFADB/MQswCQYDVQQGEwJV
-----END CERTIFICATE-----

It prints the header and footer of all cert + first line of cert.

Not exactly whats requested, but should be ok for the purpose of hiding the cert, and works with multiple cert in same pem file and multiple length of cert.

Or this is more correct (no counting lines, only awk)

awk '/-----BEGIN/ {f=2} f-->0; /-----END/ {print "****************************************************************\n" p "\n" $0}  {p=$0}' etc/auth/server.pem
-----BEGIN CERTIFICATE-----
MII8MjCCAhoCCQDGQsEmfeBvJTANBgkqhkiG9w0BAQsFADB/MQswCQYDVQQGEwJV
****************************************************************
WW/14Mz4
-----END CERTIFICATE-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIF8jBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIpS+A9Ql+5uUCAggA
****************************************************************
d9k=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MII8ejCCAmICCQCNHBN8tj/FwzANBgkqhkiG9w0BAQsFADB/MQswCQYDVQQGEwJV
****************************************************************
ZZc1oaC0PKSzBmq+TpbR27B8Zra3gpoA+gavdRZj
-----END CERTIFICATE-----


awk '
  /-----BEGIN/ {f=2}
  f-->0; 
  /-----END/ {print "****************************************************************\n" p "\n" $0}
  {p=$0}
  ' etc/auth/server.pem
Jotne
  • 40,548
  • 12
  • 51
  • 55