File: bincrypter.sh

package info (click to toggle)
bincrypter 1.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 164 kB
  • sloc: sh: 722; makefile: 6
file content (378 lines) | stat: -rwxr-xr-x 18,913 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#! /usr/bin/env bash

# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version. You should
# have received a copy of the GNU General Public License along with
# this program. If not, see https://www.gnu.org/licenses/gpl.html
#
# curl -SsfL https://github.com/hackerschoice/bincrypter/releases/latest/download/bincrypter -o bincrypter
# chmod +x bincrypter
# ./bincrypter -h
#
#
# https://github.com/hackerschoice/bincrypter

[ -t 2 ] && {
CDR="\033[0;31m" # red
CDG="\033[0;32m" # green
CDY="\033[0;33m" # yellow
CDM="\033[0;35m" # magenta
CM="\033[1;35m" # magenta
CDC="\033[0;36m" # cyan
CN="\033[0m"     # none
CF="\033[2m"     # faint
}

# %%BEGIN_BC_ALL%%
_bc_usage() {
    local bc="${0##*/}"
    echo -en >&2 "\
${CM}Encrypt or obfuscate a binary or script.${CDM}

${CDG}Usage:${CN}
${CDC}${bc} ${CDY}[-hql] [file] [password]${CN}
   -h   This help
   -q   Quiet mode (no output)
   -l   Lock binary to this system & UID and fail if copied.
        On failure, do not execute the encrypted binary. Instead:
        1. exit with 0 if BC_LOCK is not set. [default]
        2. exit with BC_LOCK if set to a numerical value.
        3. Execute BC_LOCK. (can be a base64 encoded strings).

${CDG}Environment variables (optional):${CN}
${CDY}PASSWORD=${CN}     Password to encrypt/decrypt.
${CDY}BC_PASSWORD=${CN}  Password to encrypt/decrypt (exported to callee).
${CDY}BC_PADDING=n${CN}  Add 0..n% of random data to the binary [default: 25].
${CDY}BC_QUIET=${CN}     See -q
${CDY}BC_LOCK=${CN}      See -l

${CDG}Examples:${CN}
Obfuscate myfile.sh:
  ${CDC}${bc} ${CDY}myfile.sh${CN}

Obfuscate /usr/bin/id (via pipe):
  ${CDC}cat ${CDY}/usr/bin/id${CN} | ${CDC}${bc}${CN} >${CDY}id.enc${CN}

Obfuscate & Lock to system. Execute 'id; uname -a' if copied (2 variants):
  1. ${CDY}BC_LOCK='id; uname -a' ${CDC}${bc} ${CDY}myfile.sh${CN}
  2. ${CDY}BC_LOCK='aWQ7IHVuYW1lIC1hCg==' ${CDC}${bc} ${CDY}myfile.sh${CN}

Encrypt myfile.sh with password 'mysecret':
  ${CDC}${bc} ${CDY}myfile.sh ${CDY}mysecret${CN}

Encrypt by passing the password as environment variable:
  ${CDY}PASSWORD=mysecret ${CDC}${bc} ${CDY}myfile.sh${CN}
"
    exit 0
} # EO _bc_usage

_bc_dogetopt() {
    [ -t 0 ] && [ $# -eq 0 ] && _bc_usage
    while getopts "hql" opt; do
        case $opt in
            h) _bc_usage ;;
            q) _OPT_BC_QUIET=1 ;;
            l) _OPT_BC_LOCK=0 ;;
            *) ;;
        esac
    done
    shift $((OPTIND - 1))
}

# %%BEGIN_BC_FUNC%%
_bincrypter() {
    local str ifn fn s c DATA P _P S HOOK _PASSWORD
    local USE_PERL=1
    local _BC_QUIET
    local _BC_LOCK

    # vampiredaddy wants this to work if dd + tr are not available:
    if [ -n "$USE_PERL" ]; then
        _bc_xdd() { [ -z "$DEBUG" ] && LANG=C perl -e 'read(STDIN,$_, '"$1"'); print;'; }
        _bc_xtr() { LANG=C perl -pe 's/['"${1}${2}"']//g;'; }
        _bc_xprintf() { LANG=C perl -e "print(\"$1\")"; }
    else
        _bc_xdd() { [ -z "$DEBUG" ] && dd bs="$1" count=1 2>/dev/null;}
        _bc_xtr() { tr -d"${1:+c}" "${2}";}
        _bc_xprintf() { printf "$@"; }
    fi

    _BC_QUIET="${BC_QUIET:-$_OPT_BC_QUIET}"
    _BC_LOCK="${BC_LOCK:-$_OPT_BC_LOCK}"

    _bc_err() {
        echo -e >&2 "${CDR}ERROR${CN}: $*"
        # Be opportunistic: Try to obfuscate but if that fails then just copy data
        # without obfuscation (cat).
        # Consider a system where there is no 'openssl' or 'perl' but the install
        # pipeline looks like this:
        # curl -fL https://foo.com/script | bincrypter -l >script
        # => We rather have a non-obfuscated binary than NONE.
        [ "$fn" = "-" ] && {
            cat    # Pass through
            return 0 # Make pipe succeed
        }
        return 255
    }
    # Obfuscate a string with non-printable characters at random intervals.
    # Input must not contain \ (or sh gets confused)
    _bc_ob64() {
        local i
        local h="$1"
        local str
        local x
        local s

        # Always start with non-printable character
        s=0
        while [ ${#h} -gt 0 ]; do
            i=$((1 + RANDOM % 4))
            str+=${h:0:$s}
            [ ${#x} -le $i ] && x=$(_bc_xdd 128 </dev/urandom | _bc_xtr '' '[:print:]\0\n\t')
            str+=${x:0:$i}
            x=${x:$i}
            h=${h:$s}
            s=$((1 + RANDOM % 3))
        done
        echo "$str"
    }

    # Obfuscate a string with `#\b`
    _bc_obbell() {
        local h="$1"
        local str
        local x
        local s

        [ -n "$DEBUG" ] && { echo "$h"; return; }
        while [ ${#h} -gt 0 ]; do
            s=$((1 + RANDOM % 4))
            str+=${h:0:$s}
            if [ $((RANDOM % 2)) -eq 0 ]; then
                str+='`! :&&'$'\b''#`' #backspace
                # Android's fake-bourne shell has problems with this line:
                # str+='`#'$'\b''`' #backspace
            else
                str+='`:||'$'\a''`' #alert/bell
            fi
            h=${h:$s}
        done
        echo "$str"
    }

    # Sets _P
    # Return 0 to continue. Otherwise caller should return.
    # May exit if bin is executed on another host (BC_LOCK).
    # This function is baked into the decrypter-hook
    _bcl_gen_p() {
        local _k
        local str
        # Binary is LOCKED to this host. Check if this is the same host to allow execution.
        [ -z "$BC_BCL_TEST_FAIL" ] && _k="$(_bcl_get)" && _P="$(echo "$1" | openssl enc -d -aes-256-cbc -md sha256 -nosalt -k "$_k" -a -A 2>/dev/null)"
        # [ -n "$DEBUG" ] && echo >&2 "_k=$_k _P=$_P"
        [ -n "$_P" ] && return 0
        [ -n "$fn" ] && {
            # sourced
            unset BCL BCV _P P S fn
            unset -f _bcl_get _bcl_verify _bcl_verify_dec
            return 255
        }
        # base64 to string
        BCL="$(echo "$BCL" | openssl base64 -d -A 2>/dev/null)"
        # Check if BCL is a number and exit with that number.
        [ "$BCL" -eq "$BCL" ] 2>/dev/null && exit "$BCL"
        # 2nd decode (optional)
        str="$(echo "$BCL" | openssl base64 -d -A 2>/dev/null)"
        BCL="${str:-$BCL}"
        exec /bin/sh -c "$BCL"
        exit 255 # FATAL
    }
    # Hack to stop VSCODE from marking _bcl_gen_p as unreached:
    :||_bcl_gen_p ""

    _bcl_gen() {
        local _k
        local p
        # P:=Encrypt(P) using _bcl_get as key
        _k="$(_bcl_get)"
        # [ -n "$DEBUG" ] && echo >&2 "_k=$_k P=$P"
        [ -z "$_k" ] && { echo -e >&2 "${CDR}ERROR${CN}: BC_LOCK not supported on this system"; return 255; }
        p="$(echo "$P" | openssl enc -aes-256-cbc -md sha256 -nosalt -k "${_k}" -a -A 2>/dev/null)"
        [ -z "$p" ] && { echo -e >&2 "${CDR}ERROR${CN}: Failed to generate BC_LOCK password"; return 255; }
        P="$p"
        str+="$(declare -f _bcl_verify_dec)"$'\n'
        str+="_bcl_verify() { _bcl_verify_dec \"\$@\"; }"$'\n'
        str+="$(declare -f _bcl_get)"$'\n'
        str+="$(declare -f _bcl_gen_p)"$'\n'
        str+="BCL='$(openssl base64 -A <<<"${_BC_LOCK}")'"$'\n'
        # Add test value
        str+="BCV='$(echo TEST-VALUE-VERIFY | openssl enc -aes-256-cbc -md sha256 -nosalt -k "B-${_k}" -a -A 2>/dev/null)'"$'\n'
    }
    # Test a key candidate and on success output the candidate to STDOUT.
    _bcl_verify_dec() {
        [ "TEST-VALUE-VERIFY" != "$(echo "$BCV" | openssl enc -d -aes-256-cbc -md sha256 -nosalt -k "B-${1}-${UID}" -a -A 2>/dev/null)" ] && return 255
        echo "$1-${UID}"
    }
    # Encrypt & Decrypt BCV for testing.
    _bcl_verify() {
        [ -z "$1" ] && return 255
        # [ "TEST-VALUE-VERIFY" != "$(echo "$BCV" | openssl enc -d -aes-256-cbc -md sha256 -nosalt -k "${1}" -a -A 2>/dev/null)" ] && return 255
        echo "$1-${UID}"
    }
    :||_bcl_verify

    # Generate a LOCK key and output it to STDOUT (if valid).
    # This script uses the above bcl_verify but the decoder uses its own
    # bcl_verify as a trampoline to call bcl_verify_dec.
    # FIXME: Consider cases where machine-id changes. Fallback to dmidecode and others....
    _bcl_get() {
        [ -z "$UID" ] && UID="$(id -u 2>/dev/null)"
        [ -f "/etc/machine-id" ] && _bcl_verify "$(cat "/etc/machine-id" 2>/dev/null)" && return
        command -v dmidecode >/dev/null && _bcl_verify "$(dmidecode -t 1 2>/dev/null | LANG=C perl -ne '/UUID/ && print && exit')" && return
        _bcl_verify "$({ ip l sh dev "$(LANG=C ip route show match 1.1.1.1 | perl -ne 's/.*dev ([^ ]*) .*/\1/ && print && exit')" | LANG=C perl -ne 'print if /ether / && s/.*ether ([^ ]*).*/\1/';} 2>/dev/null)" && return
        _bcl_verify "$({ blkid -o export | LANG=C perl -ne '/^UUID/ && s/[^[:alnum:]]//g && print && exit';} 2>/dev/null)" && return
        _bcl_verify "$({ fdisk -l | LANG=C perl -ne '/identifier/i && s/[^[:alnum:]]//g && print && exit';} 2>/dev/null)" && return
    }

    fn="-"
    [ "$#" -gt 0 ] && fn="$1" # $1 might be '-'
    [ "$fn" != "-" ] && [ ! -f "$fn" ] && { _bc_err "File not found: $fn"; return; }
    [ "$fn" != "-" ] && [ ! -r "$fn" ] && { _bc_err "File not readable: $fn"; return; }

    [ -n "$BC_BCL_TEST_FAIL_COMMAND" ] && { _bc_err "$BC_BCL_TEST_FAIL_COMMAND is required (fn=$fn)"; return; }
    command -v openssl >/dev/null || { _bc_err "openssl is required"; return; }
    command -v perl >/dev/null || { _bc_err "perl is required"; return; }
    command -v gzip >/dev/null || { _bc_err "gzip is required"; return; }
    [ ! -c "/dev/urandom" ] && { _bc_err "/dev/urandom is required"; return; }

    # Auto-generate password if not provided
    _PASSWORD="${2:-${PASSWORD:-$BC_PASSWORD}}"

    [ -n "$_BC_LOCK" ] && [ -n "$_PASSWORD" ] && { echo -e >&2 "${CDR}WARN${CN}: ${CDY}PASSWORD${CN} is ignored when using ${CDY}BC_LOCK${CN}."; unset _PASSWORD; }
    [ -z "$_PASSWORD" ] && P="$(DEBUG='' _bc_xdd 32 </dev/urandom | openssl base64 -A | _bc_xtr '^' '[:alnum:]' | DEBUG='' _bc_xdd 16)"
    _P="${_PASSWORD:-$P}"
    [ -z "$_P" ] && { _bc_err "No ${CDC}PASSWORD=<password>${CN} provided and failed to generate one."; return; }
    unset _PASSWORD
    # [ -n "$DEBUG" ] && echo >&2 "generated P=${P}"

    # Auto-generate SALT
    S="$(DEBUG='' _bc_xdd 32 </dev/urandom | openssl base64 -A | _bc_xtr '^' '[:alnum:]' | DEBUG='' _bc_xdd 16)"

    # base64 encoded decrypter
    HOOK='Zm9yIHggaW4gb3BlbnNzbCBwZXJsIGd1bnppcDsgZG8KICAgIGNvbW1hbmQgLXYgIiR4IiA+L2Rldi9udWxsIHx8IHsgZWNobyA+JjIgIkVSUk9SOiBDb21tYW5kIG5vdCBmb3VuZDogJHgiOyByZXR1cm4gMjU1OyB9CmRvbmUKdW5zZXQgZm4gX2VycgppZiBbIC1uICIkWlNIX1ZFUlNJT04iIF07IHRoZW4KICAgIFsgIiRaU0hfRVZBTF9DT05URVhUIiAhPSAiJHtaU0hfRVZBTF9DT05URVhUJSI6ZmlsZToiKn0iIF0gJiYgZm49IiQwIgplbGlmIFsgLW4gIiRCQVNIX1ZFUlNJT04iIF07IHRoZW4KICAgIChyZXR1cm4gMCAyPi9kZXYvbnVsbCkgJiYgZm49IiR7QkFTSF9TT1VSQ0VbMF19IgpmaQpmbj0iJHtCQ19GTjotJGZufSIKWFM9IiR7QkFTSF9FWEVDVVRJT05fU1RSSU5HOi0kWlNIX0VYRUNVVElPTl9TVFJJTkd9IgpbIC16ICIkWFMiIF0gJiYgdW5zZXQgWFMKWyAteiAiJGZuIiBdICYmIFsgLXogIiRYUyIgXSAmJiBbICEgLWYgIiQwIiBdICYmIHsKICAgIGVjaG8gPiYyICdFUlJPUjogU2hlbGwgbm90IHN1cHBvcnRlZC4gVHJ5ICJCQ19GTj1GaWxlTmFtZSBzb3VyY2UgRmlsZU5hbWUiJwogICAgX2Vycj0xCn0KX2JjX2RlYygpIHsKICAgIF9QPSIke1BBU1NXT1JEOi0kQkNfUEFTU1dPUkR9IgogICAgdW5zZXQgXyBQQVNTV09SRCAKICAgIGlmIFsgLW4gIiRQIiBdOyB0aGVuCiAgICAgICAgaWYgWyAtbiAiJEJDViIgXSAmJiBbIC1uICIkQkNMIiBdOyB0aGVuCiAgICAgICAgICAgIF9iY2xfZ2VuX3AgIiRQIiB8fCByZXR1cm4KICAgICAgICBlbHNlCiAgICAgICAgICAgIF9QPSIkKGVjaG8gIiRQInxvcGVuc3NsIGJhc2U2NCAtQSAtZCkiCiAgICAgICAgZmkKICAgIGVsc2UKICAgICAgICBbIC16ICIkX1AiIF0gJiYgewogICAgICAgICAgICBlY2hvID4mMiAtbiAiRW50ZXIgcGFzc3dvcmQ6ICIKICAgICAgICAgICAgcmVhZCAtciBfUAogICAgICAgIH0KICAgIGZpCiAgICBbIC1uICIkQyIgXSAmJiB7CiAgICAgICAgbG9jYWwgc3RyCiAgICAgICAgc3RyPSIkKGVjaG8gIiRDIiB8IG9wZW5zc2wgZW5jIC1kIC1hZXMtMjU2LWNiYyAtbWQgc2hhMjU2IC1ub3NhbHQgLWsgIkMtJHtTfS0ke19QfSIgLWEgLUEgMj4vZGV2L251bGwpIgogICAgICAgIHVuc2V0IEMKICAgICAgICBbIC16ICIkc3RyIiBdICYmIHsKICAgICAgICAgICAgWyAtbiAiJEJDTCIgXSAmJiBlY2hvID4mMiAiRVJST1I6IERlY3J5cHRpb24gZmFpbGVkLiIKICAgICAgICAgICAgcmV0dXJuIDI1NQogICAgICAgIH0KICAgICAgICBldmFsICIkc3RyIgogICAgICAgIHVuc2V0IHN0cgogICAgfQogICAgWyAtbiAiJFhTIiBdICYmIHsKICAgICAgICBleGVjIGJhc2ggLWMgIiQocHJpbnRmICVzICIkWFMiIHxMQU5HPUMgcGVybCAtZSAnPD47PD47cmVhZChTVERJTiwkXywxKTt3aGlsZSg8Pil7cy9CMy9cbi9nO3MvQjEvXHgwMC9nO3MvQjIvQi9nO3ByaW50fSd8b3BlbnNzbCBlbmMgLWQgLWFlcy0yNTYtY2JjIC1tZCBzaGEyNTYgLW5vc2FsdCAtayAiJHtTfS0ke19QfSIgMj4vZGV2L251bGx8TEFORz1DIHBlcmwgLWUgInJlYWQoU1RESU4sXCRfLCAke1I6LTB9KTtwcmludCg8PikifGd1bnppcCkiCiAgICB9CiAgICBbIC16ICIkZm4iIF0gJiYgWyAtZiAiJDAiIF0gJiYgewogICAgICAgIHpmPSdyZWFkKFNURElOLFwkXywxKTt3aGlsZSg8Pil7cy9CMy9cbi9nO3MvQjEvXFx4MDAvZztzL0IyL0IvZztwcmludH0nCiAgICAgICAgcHJnPSJwZXJsIC1lICc8Pjs8PjskemYnPCckezB9J3xvcGVuc3NsIGVuYyAtZCAtYWVzLTI1Ni1jYmMgLW1kIHNoYTI1NiAtbm9zYWx0IC1rICcke1N9LSR7X1B9JyAyPi9kZXYvbnVsbHxwZXJsIC1lICdyZWFkKFNURElOLFxcXCRfLCAke1I6LTB9KTtwcmludCg8PiknfGd1bnppcCIKICAgICAgICBMQU5HPUMgZXhlYyBwZXJsICctZSReRj0yNTU7Zm9yKDMxOSwyNzksMzg1LDQzMTQsNDM1NCl7KCRmPXN5c2NhbGwkXywkIiwwKT4wJiZsYXN0fTtvcGVuKCRvLCI+Jj0iLiRmKTtvcGVuKCRpLCInIiRwcmciJ3wiKTtwcmludCRvKDwkaT4pO2Nsb3NlKCRpKXx8ZXhpdCgkPy8yNTYpOyRFTlZ7IkxBTkcifT0iJyIkTEFORyInIjtleGVjeyIvcHJvYy8kJC9mZC8kZiJ9IiciJHswOi1weXRob24zfSInIixAQVJHVjtleGl0IDI1NScgLS0gIiRAIgogICAgfQogICAgWyAtZiAiJHtmbn0iIF0gJiYgewogICAgICAgIHVuc2V0IC1mIF9iY2xfZ2V0IF9iY2xfdmVyaWZ5IF9iY2xfdmVyaWZ5X2RlYwogICAgICAgIHVuc2V0IEJDTCBCQ1YgXyBQIF9lcnIKICAgICAgICBldmFsICJ1bnNldCBfUCBTIFIgZm47JChMQU5HPUMgcGVybCAtZSAnPD47PD47cmVhZChTVERJTiwkXywxKTt3aGlsZSg8Pil7cy9CMy9cbi9nO3MvQjEvXHgwMC9nO3MvQjIvQi9nO3ByaW50fSc8IiR7Zm59InxvcGVuc3NsIGVuYyAtZCAtYWVzLTI1Ni1jYmMgLW1kIHNoYTI1NiAtbm9zYWx0IC1rICIke1N9LSR7X1B9IiAyPi9kZXYvbnVsbHxMQU5HPUMgcGVybCAtZSAicmVhZChTVERJTixcJF8sICR7UjotMH0pO3ByaW50KDw+KSJ8Z3VuemlwKSIKICAgICAgICByZXR1cm4KICAgIH0KICAgIFsgLXogIiRmbiIgXSAmJiByZXR1cm4KICAgIGVjaG8gPiYyICJFUlJPUjogRmlsZSBub3QgZm91bmQ6ICRmbiIKICAgIF9lcnI9MQp9ClsgLXogIiRfZXJyIiBdICYmIF9iY19kZWMgIiRAIgp1bnNldCBmbgp1bnNldCAtZiBfYmNfZGVjCmlmIFsgLW4gIiRfZXJyIiBdOyB0aGVuCiAgICB1bnNldCBfZXJyCiAgICBmYWxzZQplbHNlCiAgICB0cnVlCmZpCg=='

    # _P - used with openssl below. AS INSERTED BY USER _or_ GENERATED.
    #  P - Generated. Stored in P=base64($P).
    # [ -n "$DEBUG" ] && echo >&2 "OpenSSL ENC with _P=$_P (P='$P')"
    unset str _C R
    # P:=Encrypted(P) using HOST-ID as encryption-key. Resets $str.
    [ -n "$_BC_LOCK" ] && _bcl_gen
    [ -z "$str" ] && {
        # NOT using BC_LOCK (Fallback)
        str="unset BCV BCL"$'\n'
        # P is not set if provided via ENV or $2
        [ -n "$P" ] && P="$(echo "$P"|openssl base64 -A 2>/dev/null)"
    }

    # Always base64 encode.
    ## Add Password to script ($P might be encrypted if BC_LOCK is set)
    [ -n "$P" ] && {
        # [ -n "$DEBUG" ] && echo >&2 "Store P=${P}"
        str+="P=${P}"$'\n'
        unset P
    }

    ## Add SALT to script
    str+="S='$S'"$'\n'

    # Bash strings are not binary safe. Instead, store the binary as base64 in memory:
    ifn="$fn"
    [ "$fn" = "-" ] && ifn="/dev/stdin"
    DATA="$(gzip <"$ifn" | openssl base64)" || return 255

    ## Add size of random padding to script (up to roughly 25% of the file size)).
    [ "$BC_PADDING" != "0" ] && {
        local sz="${#DATA}"
        [ "$sz" -lt 31337 ] && sz=31337
        R="$(( (RANDOM * 32768 + RANDOM) % ((sz / 100) * ${BC_PADDING:-25})))"
    }
    _C+="R=${R:-0}"$'\n'

    ## Add encrypted configs to script
    [ -n "$_C" ] && {
        [ -n "$DEBUG" ] && echo >&2 "Store C=ENC('${_C}')"
        str+="C=$(echo "$_C" | openssl enc -aes-256-cbc -md sha256 -nosalt -k "C-${S}-${_P}" -a -A 2>/dev/null)"$'\n'
    }

    str+="$(echo "$HOOK"|openssl base64 -A -d)"
    [ -n "$DEBUG" ] && { echo -en >&2 "DEBUG: ===code===\n${CDM}${CF}"; echo >&2 "$str"; echo -en >&2 "${CN}"; }
    ## Encode & obfuscate the HOOK
    HOOK="$(echo "$str" | openssl base64 -A)"
    HOOK="$(_bc_ob64 "$HOOK")"

    [ -z "$_BC_QUIET" ] && [ "$fn" != "-" ] && { 
        s="$(stat -c %s "$fn")"
        [ "$s" -gt 0 ] || { _bc_err "Empty file: $fn"; return; }
    }

    [ "$fn" = "-" ] && fn="/dev/stdout"

    # Create the encrypted binary: /bin/sh + Decrypt-Hook + Encrypted binary
    { 
        # printf '#!/bin/sh\0#'
        # Add some binary data after shebang, including \0 (sh reads past \0 but does not process. \0\n count as new line).
        # dd count="${count:-1}" bs=$((1024 + RANDOM % 1024)) if=/dev/urandom 2>/dev/null| tr -d "[:print:]\n'"
        # echo "" # Newline
        # => Unfortunately some systems link /bin/sh -> bash.
        # 1. Bash checks that the first line is binary free.
        # 2. and no \0 in the first 80 bytes (including the #!/bin/sh)
        echo '#!/bin/sh'
        # Add dummy variable containing garbage (for obfuscation) (2nd line)
        echo -n "_='" 
        _bc_xdd 66 </dev/urandom | _bc_xtr '' "[:print:]\0\n'"
        # \0\0 confuses some shells.
        _bc_xdd "$((1024 + RANDOM % 4096))" </dev/urandom| _bc_xtr '' "[:print:]\0{2,}\n'"
        # _bc_xprintf "' \x00" # WORKS ON BASH ONLY
        _bc_xprintf "';" # works on BASH + ZSH
        # far far far after garbage
        ## Add my hook to decrypt/execute binary
        # echo "eval \"\$(echo $HOOK|strings -n1|openssl base64 -d)\""
        echo "$(_bc_obbell 'eval "')\$$(_bc_obbell '(echo ')$HOOK|LANG=C $(_bc_obbell "perl -pe \"s/[^[:print:]]//g\"")$(_bc_obbell "|openssl base64 -A -d)")\""
        # Add the encrypted binary (from memory)
        # ( DEBUG='' _bc_xdd "${R:-0}" </dev/urandom; openssl base64 -d<<<"$DATA") |openssl enc -aes-256-cbc -md sha256 -nosalt -k "${S}-${_P}" 2>/dev/null | LANG=C perl -pe 's/B/B2/g; s/\x00/B1/g'
 
        # To support 'BC_FN=h.sh eval "$(<h.sh)"' we need to have all binary data in one single
        # line and pre-fixed with '#' to prevent execution.
        echo -n '#'
        ( DEBUG='' _bc_xdd "${R:-0}" </dev/urandom; openssl base64 -d<<<"$DATA") |openssl enc -aes-256-cbc -md sha256 -nosalt -k "${S}-${_P}" 2>/dev/null | LANG=C perl -pe 's/B/B2/g; s/\x00/B1/g; s/\n/B3/g'
    } > "$fn"

    [ -n "$s" ] && {
        c="$(stat -c %s "$fn" 2>/dev/null)"
        [ -n "$c" ] && echo -e >&2 "${CDY}Compressed:${CN} ${CDM}$s ${CF}-->${CN}${CDM} $c ${CN}[${CDG}$((c * 100 / s))%${CN}]"
    }
    # [ -z "$_BC_QUIET" ] && [ -n "$_BC_LOCK" ] && echo -e >&2 "${CDY}PASSWORD=${CF}${_P}${CN}"
    unset -f _bc_usage _bcl_get _bcl_verify _bcl_verify_dec _bc_err _bc_ob64 _bc_obbell _bc_xdd _bc_xtr _bc_xprintf
    [ -z "$_BC_QUIET" ] && echo -e >&2 "${CDG}Done${CN}"
    return 0
}
# %%END_BC_FUNC%%

# Check if sourced or executed
[ -n "$ZSH_VERSION" ] && [ "$ZSH_EVAL_CONTEXT" != "${ZSH_EVAL_CONTEXT%":file:"*}" ] && _sourced=1
(return 0 2>/dev/null) && _sourced=1
[ -z "$_sourced" ] && {
    # Execute if not sourced:
    _bc_dogetopt "$@"
    _bincrypter "$@"
    exit
}

### HERE: sourced
bincrypter() {
    _bc_dogetopt "$@"
    _bincrypter "$@"
}
unset _sourced