8

I'm trying to make a batch file from CMD with the following commands:

  1. Convert file to base 64 - using certutil command this is how the contents of the base 64 looks like (B64.txt):

converted B64.txt

  1. Trim the base 64 - basically, I want to remove -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- this part is done, the only thing left is trim the newline characters to make a one liner of base64, because I will be passing this to a request payload.

This is what I did so far:

@ECHO OFF 
cd /filePath
certutil -encode sample.pdf B64.txt
type B64.txt | find /V "-----BEGIN CERTIFICATE-----" | find /V "-----END CERTIFICATE-----" > B64.txt

My question is:

  1. Using the command find /V* how can I define the new line characters and remove them?

  2. Is there a more efficient way to do this?

Can this also be done without assigning the base 64 as a variable? It turns out that the limit for variables is only around 9000 characters, and the base 64 I convert normally has 70,000 characters.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
so_mc
  • 149
  • 1
  • 7
  • For variable, check the limit length [here](https://stackoverflow.com/questions/3205027/maximum-length-of-command-line-string) – Io-oI Feb 25 '20 at 08:56
  • Can you read a file at the beginning of a pipe and write to the same file at the end of the pipeline? – lit Feb 25 '20 at 15:28
  • Do not paste images of text. https://meta.stackoverflow.com/questions/303812/discourage-screenshots-of-code-and-or-errors – Jonathan Hall May 09 '20 at 11:33

4 Answers4

27

There is a really simple solution using undocumented features of CERTUTIL. You can use the
-ENCODEHEX verb with an undocumented format at the end to directly get your desired output of base 64 all on one line without any headers.

certutil -encodehex -f sample.pdf B64.txt 0x40000001

See the DosTips More Tricks with certutil thread for more information. Especially look at this 4th post for a detailed explanation of all the format options.

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • 2
    Undocumented methods can make things happen. And I do not know how many people on the level of @dbenham regarding cmd.exe. However, undocumented methods present a risk. Since they are undocumented, there is no obligation for the provider of the utility to keep them. – lit Feb 28 '20 at 16:21
  • 3
    @lit - I said the format option was undocumented, but that is not entirely true. `certutil -encodehex /?` lists an optional `type` option, but doesn't describe what the values can be. The Windows32 API documentation for the [CryptBinaryToStringA function](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptbinarytostringa?redirectedfrom=MSDN) describes most of the options. It's a small leap of faith relating CERTUTIL to CryptBinaryToStringA, but the options are probably reliable. – dbenham Feb 28 '20 at 20:08
  • Beautiful answer – Desolator Nov 11 '21 at 04:29
  • This answer is a gold. No need to install anything or mess with powershell scripts. – Hitesh Kumar Saini Aug 19 '22 at 20:53
2
  • Edit:

You can use a / file with a code.

Then you will compile it and run it at run time to get all the strings in one line ...

  • Usage:

1) Edit: cd /d "D:\Path\to\file\", adding the drive:\and\path\to\your\directory

2) Save this code below as File OneLine.cmd

/* 2>nul & @cls & @echo off & title <nul & title %~nx0 & setlocal enabledelayedexpansion

cd /d "D:\Path\to\file\" && set "_b64_file=%__CD__%\B64.txt"
"%__APPDIR__%certutil.exe" -encode -f ".\sample.pdf" "!_b64_file!" >nul 
for /f "tokens=*" %%c in ('%__APPDIR__%where.exe /r "c:\Windows\Microsoft.NET" csc.exe
')do >2nul >nul "%%~c" /t:exe /out:"%tmp%\OneLine.exe" "%~f0" /platform:anycpu /unsafe+ /w:0 /o /nologo && goto :next

:next 
"%tmp%\OneLine.exe" & 2>nul >nul del /q /f "%tmp%\OneLine.exe" & endlocal && goto :EOF || rem :: */

using System; using System.IO;using System.Text;namespace OneLineB64 {class Program {static void Main(string[] args){
String Path = System.Environment.GetEnvironmentVariable("_b64_file");String alllines = (File.ReadAllText(Path).Replace(Environment.NewLine, ""));
alllines = alllines.Remove(0,27); alllines = alllines.Remove((alllines.Length)-25);File.WriteAllText(Path, alllines);}}}
  • Same code in conventional formatting/layout
/* 2>nul & @cls

@echo off 

title <nul
title %~nx0

setlocal enabledelayedexpansion

cd /d "D:\Path\to\file\"
set "_b64_file=%__CD__%\B64.txt"

"%__APPDIR__%certutil.exe" -encode -f ".\sample.pdf" "!_b64_file!" >nul 

for /f "tokens=*" %%c in ('%__APPDIR__%where.exe /r "c:\Windows\Microsoft.NET" csc.exe')do (
   >2nul >nul "%%~c" /t:exe /out:"%tmp%\OneLine.exe" "%~f0" /platform:anycpu /unsafe+ /w:0 /o /nologo && goto :next
   )

:next 
"%tmp%\OneLine.exe"
2>nul >nul del /q /f "%tmp%\OneLine.exe" 

endlocal
goto :EOF

*/

using System;
using System.IO;
using System.Text;

namespace OneLineB64
{
    class Program
    {
        static void Main(string[] args)
        {
         String Path = System.Environment.GetEnvironmentVariable("_b64_file");
         String alllines = (File.ReadAllText(Path).Replace(Environment.NewLine, ""));
         alllines = alllines.Remove(0,27); 
         alllines = alllines.Remove((alllines.Length)-25);
         File.WriteAllText(Path, alllines);
        }
    }
}


File Class

SubString/Remove Characters in String

Get System Environment Variable string

Environment.GetEnvironmentVariable Method


  • /end Edit:

Understanding the maximum character limit in the variable length, it is not possible to do it beyond 8191 digits/characters


For remove lines you can use only certificate, because this word is present in 1st and last line.

certutil + -f for overwrite file out if exist

type B64.txt^|"%__APPDIR__%find.exe" /v "CERTIFICATE" will ignore the 1st and last line

set "_b64=!_b64!%%~b" will save line by line in the same variable/1 line

>B64.txt echo/!_b64! will replace/overwrite the contents of the file with the value saved in the variable (b64 strings on one line)

@echo off && setlocal enabledelayedexpansion

cd /d "d:\filePath" && set "_b64="<nul

"%__APPDIR__%certutil.exe" -encode -f sample.pdf B64.txt >nul && for /f %%b in (
'type B64.txt^|"%__APPDIR__%find.exe" /v "CERTIFICATE"')do set "_b64=!_b64!%%~b"

>B64.txt set/p "'=!_b64: =!"<nul & endlocal && exit /b 

Same code in conventional layout:

@echo off

setlocal enabledelayedexpansion

cd /d "d:\filePath"
set "_b64="<nul

"%__APPDIR__%certutil.exe" -encode -f sample.pdf B64.txt >nul

for /f %%b in ('type B64.txt^|"%__APPDIR__%find.exe" /v "CERTIFICATE"')do set "_b64=!_b64!%%~b"

>B64.txt set/p "'=!_b64: =!"<nul 

endlocal
goto :EOF

Io-oI
  • 2,514
  • 3
  • 22
  • 29
  • Right, but how is it that there's a space and a new line in the end of the file? Can you check your generated B64.txt? Maybe a problem in my CMD? – so_mc Feb 25 '20 at 08:50
  • Hello, sorry I didn't test it properly, but it seems that there was a problem with the file, whenever I try to decode the file back to PDF, it returns an unreadable PDF. I investigated further and tried to manually encode the PDF to base64, and I got a total length of 69,284 characters, while your code only produced 8,164 characters, why is this? Maybe it's trimming not only the new lines, but also some characters in the file. – so_mc Feb 25 '20 at 10:12
  • @so_mc have you read my comment in your question? About variable limits? You can’t use cmd/bat for strings with this length in a variable, also, how to you add content to line without using any variable?. So, try using breaking line with escaping in the language you are apply this, or, put another question. – Io-oI Feb 25 '20 at 10:21
  • Sorry, I didn't notice it earlier, so what I want isn't possible? Can't this be done without using variables? – so_mc Feb 25 '20 at 10:39
  • Yeah okay, and another thing, the part on how it trims the variable is also weird, the reason why I assumed that the converted base 64 was right was because the starting and ending characters are the same, so that means the 60,000+ characters were from the middle section, right? – so_mc Feb 25 '20 at 10:57
  • Oh okay, it's just kinda hard to digest everything when I don't know much about CMD CLI :( but nonetheless, if you think this is workable, I'll also try to look for alternate solution while you work on yours. Thanks! – so_mc Feb 25 '20 at 11:14
  • can you please elaborate more on how I can use this? Will I save this c# code in a bat file and then what? What parts will I replace with my path? Can you provide at least step by step? I don't get it sorry I'm quite new with this approach. Thanks! – so_mc Feb 25 '20 at 20:41
  • @so_mc this is a bat file and C#, bat save as file.bat or file.cmd and run... – Io-oI Feb 25 '20 at 21:06
1

This may do what you want. If you are on a supported Windows system, PowerShell will be available.

SET "FILENAME=C:\src\t\sample.pdf"
SET "OUTFILENAME=C:\src\t\B64.txt"

powershell -NoLogo -NoProfile -Command ^
    "[Convert]::ToBase64String([IO.File]::ReadAllBytes('%FILENAME%')) |" ^
        "Out-File -FilePath '%OUTFILENAME%' -Encoding ascii -NoNewline"
lit
  • 14,456
  • 10
  • 65
  • 119
0

Can you send link to B64.txt or content of filePath or paste text here? My OCR can't get 100% conversion, even Google Lens can't.

My understanding is you need a base 64 code in one line without headers, right?

Certutil can handle 70k chars. set /p to avoid new lines.
One line output for base64 without cert headers example:

certutil -f -encodehex "Fujitsu Air Con Manual.pdf" test.b64 1
for /f %i in (test.b64) do set /p=%i<nul

One line base 64 dump Output may be redirected to file or via pipe for "passing this to a request payload"

Tested on Win 10: @ 2.5 Million characters.

dir test.b64
 Volume in drive C is Local Disk
 Volume Serial Number is 74F6-ACFC

 Directory of C:\Users\Al\Desktop

05/05/2022  12:12         **2,677,662** test.b64
               1 File(s)      2,677,662 bytes
               0 Dir(s)  54,901,383,168 bytes free

for /f %i in (test.b64) do set /p=%i<nul>> one.line
dir one.line
 Volume in drive C is Local Disk
 Volume Serial Number is 74F6-ACFC

 Directory of C:\Users\Al\Desktop

05/05/2022  13:00         **2,596,560** one.line
               1 File(s)      2,596,560 bytes
               0 Dir(s)  54,812,700,672 bytes free
Zimba
  • 2,854
  • 18
  • 26