topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • Thursday September 10, 2026, 8:58 am
  • Proudly celebrating 15+ years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: KeyExchange: Incompatibility with Fish_10 and PZS-NG  (Read 465 times)

Rhino Cracker

  • Participant
  • Joined in 2026
  • *
  • Posts: 2
    • View Profile
    • Donate to Member
KeyExchange: Incompatibility with Fish_10 and PZS-NG
« on: February 10, 2026, 02:27 PM »
Hi all,
I'm a long-time user of Mircryption since my early days in IRC.
I think since "Operation Boxenstopp" in 2006, which made everyone panick. :D

I was expieriencing some difficulties using glftpd's sitebot pzs-ng, lately:
In the most recent versions, it:
- refuses to talk to me,
- refuses to invite me.
After a key-exchange has been triggered by me or the sitebot itself.

I've reported it, but I don't think it will ever be fixed, because most people seem to use Fish_10 now.
Bug-Ticket: https://github.com/g...tpd/pzs-ng/issues/47


Details:

On my journey of trying to debug this, I have uncovered some incompatibilities between pzs-ng's, weechat's, fish_10's and Mircryption's key-exchange mechanism and fallbacks to ECB.

In short, from my memory, from one month ago:
- DH1080_INIT <pubKey> and DH1080_FINISH <encryptedSecret> work with all versions to exchange a key and use it for ECB mode BlowFish encryption.
- Mircryption uses DH1080_INIT_cbc <pubKey> and DH1080_FINISH_cbc <encryptedSecret> to exchange keys with the intention to use it for CBC encrypted chats. I'd call this syntax Mircryption's syntax or command suffix syntax.
- Fish_10 and PZS-NG seem to use DH1080_INIT <pubKey> CBC and DH1080_FINISH <encryptedSecret> CBC to exchange keys with the intention to use it for CBC encrypted chats. I'd call this syntax Fish syntax or key suffix syntax.
- Some implementations (Weechat?) seem to exchange without any CBC suffix, but just enable sending in CBC mode by default and decode anything that arrives with a * as first character in CBC mode and anything else in ECB mode. So they switch without further noticing the user about using less secure ECB...

What happens now when Fish_10 or PZS-NG initiate a key-exchange with Mircryption in CBC mode?
- partner sends DH1080_INIT <pubKey> CBC
- Mircryption ignores the CBC key suffix, treats this as an ECB exchange and answers with a ECB finish: DH1080_FINISH <encryptedSecret>
- Fish_10 falls back to ECB mode, PZS-NG is not being triggered by the answer, waits endlessly, blocks pms and invites...

If Mircryption triggers the exchange:
- Mircryption sends DH1080_INIT_cbc <pubKey>
- partner ignores the request at all (PZS-NG) OR ignores the command suffix (Fish_10), misinterprets it as ECB exchange and answers with ECB finish: DH1080_FINISH <encryptedSecret>

I've also found out: when I "patch" this, so mircryption can also initiate a key-exchange in Fish-syntax or respond to Fish-syntax with Fish-syntax, PZS-NG seems to exchange in CBC mode, but just sends in ECB mode anyways...
Mircryption will just show "ERROR_NONCBC: <garbage>", while FIsh_10 just detects the non-cbc messages by the missing * and decrypts it in ECB mode without further notice...


Solution and Questions:

1. I have "patched" this, so it can do key-exchanges in fish syntax: initiate them AND respond to them "properly". However, I'm not fully sure if this is the "right" way to handle this, because I cannot find a standard specifying it... Do you want me to make it "presentable" (remove the debug outputs) and provide it to you?

2. Do you think it is the right way/solution?

3. I'm mostly a C-coder, my MSL-skills are pretty rusty and I could really benefit from a code review! Is anyone volunteering for a review?

4. Is Mouser still alive? Does he maybe want to integrate this into his package?

5. How do you think Mircryption should handle a partner sending in ECB mode, when CBC has been exchanged, or vice versa?
- just show a error message and garbage, as now? (security solution)
- automatically decrypt in correct mode? (so auto switch to ECB/CBC decryption depending on encrypted input string: * prefix and possible = suffices) (compatibility solution)
- show an error message for wrong mode AND decrypt in mode indicated by prefix? (mix of compatibility and security)
- use specific styling to differentiate between ECB, CBC and plain text messages?
- should it also switch its configured sending mode, when other mode messages arrive? (risky mode: enforced fallback to ECB possible)

Rhino Cracker

  • Participant
  • Joined in 2026
  • *
  • Posts: 2
    • View Profile
    • Donate to Member
Re: KeyExchange: Incompatibility with Fish_10 and PZS-NG
« Reply #1 on: May 11, 2026, 03:42 PM »
So this is my edited mcpsFishDH.mrc
Spoiler
; ---------------------------------------------------------------------------
; MircryptionSuite - McpsFishDH addon v. 1.01.00 - dh key exchange
;
; see installation instructions at end of this readme.
;
; 06/01/03, mirc script by Dark Raichu, http://mircryption.sourceforge.net
; 12/05/03, Updated to use the new fish.dll which does 1024 bit keys and is *reportedly* safer.
; 12/20/03, Fixing some bugs that were preventing script from working if not in main mirc directory.
; 12/29/03, Added better error reporting.
; 02/02/04, updated to point to official fish site - thanks to author of fish
;           for informing me of its location and for making the fish source code publically available.
; 04/23/04, updated with new 1080 version of fish.dll
;           changed name of script.
; 05/24/04, message about old version was causing harmless annoying mirc error
; 01/18/05, adding dh support for cbc keys
; 01/22/05, added proper version reporting
; 01/24/05, added menu+switch for old style key exchange (may be useful for talking with dhfish eggdrops)
; 02/15/05, cleaned up a temp var, fixed rand chan key
; 11/04/05, fixed bug with multiserv nicks reporting no keyexchange in progress
; 01/14/26, Rhino: added support for fish_10 cbc syntax, also used by pzs-ng/glftpd/...
; MM/DD/YY?
; ---------------------------------------------------------------------------

; ---------------------------------------------------------------------------
; IMPORTANT:
; This addon uses the fish.dll which was written by [anonymous]/
;  it comes with version 1.25 of fish, but you should go get the LATEST
;  fish.dll from the original fish author here:
;  ----> http://fish.sekure.us
; Grab the standalone fish dh download and copy the fish.dll into the McpsFishDH directory.
; ---------------------------------------------------------------------------

; ---------------------------------------------------------------------------
; this mirc script (not the dll) is based on mirc code originally started by Sinner
;  and then continued by [anonymous]. the original credits section of blow.mrc:
;     "Big thanks go out to nutty for all his help
;      and to Joffi for his additional ideas
;      And even more thanks go out to mpyx, who helped me alot implementing
;      the secure keyXchange feature.
;      _SiNnEr_ 04-10-2003"
;
; Most of the work is done by the Fish.dll, which was written by [anonymous]
;  and uses code from the MIRACL C library.  thanks for making fish available to all of us.
; ---------------------------------------------------------------------------

;;---------------------------------------------------------------------------
;; IMPORTANT: [anonymous] has released the source code for fish(!) this is
;;  great news and means that the code can be validated if you have any
;;  question about it's integrity.  Still, USE THIS AT YOUR OWN RISK(!)
;;  ----> http://fish.sekure.us
;;---------------------------------------------------------------------------


;;---------------------------------------------------------------------------
;This addon is being provided to add compatibility between mircryption and
; blow, and to allow easier key exchange than mpgp.  Version 2 of mircryption
; will add it's own builtin secure key exchange that operates similarly.
;;---------------------------------------------------------------------------

;---------------------------------------------------------------------------
Installation:
0. Unload and delete any old version of mircryption_SinnerFishDH.mrc, this is
an old version and will interfere with the new version if you unload it
/unload -rs mircryption_SinnerFishDH.mrc
1. Copy the McpsFishDH directory to your mirc directory
2. From inside mirc do /load -rs McpsFishDH/mcpsFishDH.mrc
3. See the new fish menu available when right clicking in a query window.
;---------------------------------------------------------------------------

;---------------------------------------------------------------------------
Usage:
open a query window with someone, see new item in right click to exchange a key.
;---------------------------------------------------------------------------













;---------------------------------------------------------------------------
on *:START: {

  ; let user know the script is loaded 
  .mcdh_about
  %mc_sinnerscriptdll = " $+ $scriptdir $+ FiSH.DLL $+ "
}
;---------------------------------------------------------------------------


; about function tells version
alias mcdh_about {
  ; script version
  %mc_sinnerdhversion = 1.00.11
  if ($dialog(mcupdater_down).hwnd != $null) did -a mcupdater_down 7 McpsFishDH addon v. %mc_sinnerdhversion loaded and ready. $+ $crlf
  echo 7 -s MircryptionSuite - McpsFishDH addon v. %mc_sinnerdhversion loaded and ready.
}


;---------------------------------------------------------------------------
menu query {
  .Mircryption McpsFishDH 1080bit keyXchange (Mircryption CBC) [/mckeyx $1 MCBC] : mcsinnerdh.dhgetpubkey $1 MCBC
  .Mircryption McpsFishDH 1080bit keyXchange (Fish CBC) [/mckeyx $1 FCBC] : mcsinnerdh.dhgetpubkey $1 FCBC
  .Mircryption McpsFishDH 1080bit keyXchange (legacy ECB) ..... [/mckeyx $1 ECB] : mcsinnerdh.dhgetpubkey $1 ECB
}

menu nicklist {
  .Mircryption McpsFishDH 1080bit keyXchange (Mircryption CBC) [/mckeyx $1 MCBC] : mcsinnerdh.dhgetpubkey $1 MCBC
  .Mircryption McpsFishDH 1080bit keyXchange (Fish CBC) [/mckeyx $1 FCBC] : mcsinnerdh.dhgetpubkey $1 FCBC
  .Mircryption McpsFishDH 1080bit keyXchange (legacy ECB) ..... [/mckeyx $1 ECB] : mcsinnerdh.dhgetpubkey $1 ECB
}

menu channel {
  &Mircryption
  .More commands..
  ..McpsFishDH - Set Random Channel Key : rndkey $chan
}
;---------------------------------------------------------------------------








;---------------------------------------------------------------------------
alias mcsinnerdh.dhgetpubkey {
  mcsinnerdh.DH1080_INIT $1 $2-
  ; ATTN: halt not needed
  ;halt
}

alias mcsinnerdh.DH1080_INIT {
  ; /echo @debug calling mcsinnerdh.DH1080_INIT with $1-
  if ( %mc_sinnerdh_disautokey == 1 ) { halt }
  set %mc_sinnerdh_dh $+ [ $mcdh_cleanmultiserve($1) ] 1
  var %tempkey $dll(%mc_sinnerscriptdll,DH1080_gen,NOT_USED)
  %mc_sinnerdh_prv_key = $gettok(%tempkey, 1, 32)
  %mc_sinnerdh_pub_key = $gettok(%tempkey, 2, 32)

  unset %tempkey
  if ( ($gotmircryptioncbc) && ($2 == MCBC) ) {
    ; Mircryption CBC init
    .notice $1 DH1080_INIT_cbc %mc_sinnerdh_pub_key
    ; /echo @debug OUT: DH1080_INIT_cbc %mc_sinnerdh_pub_key
  }
  elseif ( ($gotmircryptioncbc) && ($2 == FCBC) ) {
    ; Fish CBC init
    .notice $1 DH1080_INIT %mc_sinnerdh_pub_key CBC
    ; /echo @debug OUT: DH1080_INIT %mc_sinnerdh_pub_key CBC
  }
  else {
    ; legacy ECB init
    .notice $1 DH1080_INIT %mc_sinnerdh_pub_key
    ; /echo @debug OUT: DH1080_INIT %mc_sinnerdh_pub_key
  }
  echo $color(Mode text) -tm $nick *** Sent my DH1080 public key to $1 $+ , waiting for reply ...
}

alias mckeyx {
  if ($1 == $null) {
    if ($$query($active)) {
      mcsinnerdh.dhgetpubkey $active
    }
  }
  else {
    mcsinnerdh.dhgetpubkey $1
  }
}
;---------------------------------------------------------------------------








;---------------------------------------------------------------------------
; NEW FISH DH Exchange Routines (1080)

on ^1:NOTICE:DH1080_INIT*:?:{
  ; /echo @debug NOTICE handler with $1-
  if ( %mc_sinnerdh_disautokey == 1 ) { halt }
 
  var %mode MCBCorFCBCorECB
  if ($1 == DH1080_INIT_cbc && $3 == $null) { %mode = MCBC }
  elseif ($1 == DH1080_INIT && $3 == CBC) { %mode = FCBC }
  elseif ($1 == DH1080_INIT && $3 == $null) { %mode = ECB }
  else { %mode = unknown }
  ; /echo @debug mode is %mode
 
  if ($len($2) == 180 || $len($2) == 181) {
    set %mc_sinnerdh_dh $+ [ $mcdh_cleanmultiserve($nick) ] 1
    echo $color(Mode text) -tm $nick *** Received DH1080 public key from $nick $+ ...
    var %tempkey $dll(%mc_sinnerscriptdll,DH1080_gen,NOT_USED)
    %mc_sinnerdh_prv_key = $gettok(%tempkey, 1, 32)
    %mc_sinnerdh_pub_key = $gettok(%tempkey, 2, 32)
    unset %tempkey

    ;/echo HEYDEBUG DH1080_INIT first word is $1
    ; /echo @debug IN: $1-

    var %secret = $dll(%mc_sinnerscriptdll,DH1080_comp, %mc_sinnerdh_prv_key $2)

    ; ATTN: set key for %nick to $secret (blow.setkey $nick %secret)
    var %retv
    if ( ( CBC isin %mode ) && ($gotmircryptioncbc) ) {
      %secret = cbc: $+ %secret
      %retv = $dll( %mc_scriptdll  , mc_setkey , $mcdh_cleanmultiserve($nick) %secret)
    }
    else {
      %retv = $dll( %mc_scriptdll  , mc_setkey , $mcdh_cleanmultiserve($nick) %secret)
    }

    if (%retv != $null) {
      ; echo 4 -s %retv
      if ( ( MCBC == %mode ) && ($gotmircryptioncbc) ) {
        echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange cbc (mircryption) complete: %retv
        .notice $nick DH1080_FINISH_cbc %mc_sinnerdh_pub_key
        ; /echo @debug OUT: DH1080_FINISH_cbc %mc_sinnerdh_pub_key
      }
      elseif ( ( FCBC == %mode ) && ($gotmircryptioncbc) ) {
        echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange cbc (fish) complete: %retv
        .notice $nick DH1080_FINISH %mc_sinnerdh_pub_key CBC
        ; /echo @debug OUT: DH1080_FINISH %mc_sinnerdh_pub_key CBC
      }
      else {
        echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange ecb complete: %retv
        .notice $nick DH1080_FINISH %mc_sinnerdh_pub_key
        ; /echo @debug OUT: DH1080_FINISH %mc_sinnerdh_pub_key
      }
    }
    else {
      echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange failed to set mircryption key.
      .notice $nick DH1080_FINISH ERROR
      ; /echo @debug OUT: DH1080_FINISH ERROR
    }

    unset %mc_sinnerdh_dh $+ [ $mcdh_cleanmultiserve($nick) ]
    unset %mc_sinnerdh_prv_key
    unset %mc_sinnerdh_pub_key
    unset %secret
  }
  else {
    echo $color(Mode text) -tm $nick *** Improper DH1080 init from $nick, aborting exchange.
  }
  halt
}



on ^1:NOTICE:DH1080_FINISH*:?:{
  ; /echo @debug NOTICE handler with $1-
  var %retv
  if ( %mc_sinnerdh_dh [ $+ [ $mcdh_cleanmultiserve($nick) ] ] != 1 ) {
    echo $color(Mode text) -tm $nick *** Received DH1080 finalization from $nick but no keyXchange is in progress - noaction taken.
    halt
  }

  ;/echo HEYDEBUG DH1080_FINISH first word is $1
  ; /echo @debug IN: $1-
 
  var %mode MCBCorFCBCorECB
  if ($1 == DH1080_FINISH_cbc && $3 == $null) { %mode = MCBC }
  elseif ($1 == DH1080_FINISH && $3 == CBC) { %mode = FCBC }
  elseif ($1 == DH1080_FINISH && $3 == $null) { %mode = ECB }
  else { %mode = unknown }
  ; /echo @debug mode is %mode

  if ($len($2) == 180 || $len($2) == 181) {
    var %secret = $dll(%mc_sinnerscriptdll,DH1080_comp, %mc_sinnerdh_prv_key $2)

    ; ATTN: set key for %nick to $secret (blow.setkey $nick %secret)

    if ( ( CBC isin %mode ) && ($gotmircryptioncbc) ) {
      %secret = cbc: $+ %secret
      %retv = $dll( %mc_scriptdll  , mc_setkey , $mcdh_cleanmultiserve($nick) %secret)
    }
    else {
      %retv = $dll( %mc_scriptdll  , mc_setkey , $mcdh_cleanmultiserve($nick) %secret)
    }

    if (%retv != $null) {
      if ( ( MCBC == %mode ) && ($gotmircryptioncbc) ) {
        echo $color(Mode text) -tm $nick *** Mircryption Fish cbc (Mircryption) keyXchange complete: %retv
      }
      elseif ( ( FCBC == %mode ) && ($gotmircryptioncbc) ) {
        echo $color(Mode text) -tm $nick *** Mircryption Fish cbc (Fish) keyXchange complete: %retv
      }
      else {
        echo $color(Mode text) -tm $nick *** Mircryption Fish ecb keyXchange complete: %retv
      }
    }
    else {
      echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange failed to set mircryption key.
    }

    unset %mc_sinnerdh_dh $+ [ $mcdh_cleanmultiserve($nick) ]
    unset %mc_sinnerdh_prv_key
    unset %mc_sinnerdh_pub_key
    unset %secret
  }
  else {
    echo $color(Mode text) -tm $nick *** Improper DH1080 reply from $nick, aborting exchange.
    ;echo $color(Mode text) -tm one is $1 and 2 is $2 and len is $len($2)
  }
  halt
}
;---------------------------------------------------------------------------













;---------------------------------------------------------------------------
; OLD FISH DH Exchange Routines

on ^1:NOTICE:DH1024_INIT*:?:{
  ; /echo @debug IN: DH1024_INIT full string is $1-
  var %retv
  if ( %mc_sinnerdh_disautokey == 1 ) { halt }
  if ($len($2) <= 172 && $len($2) >= 170) {
    set %mc_sinnerdh_dh $+ [ $mcdh_cleanmultiserve($nick) ] 1
    echo $color(Mode text) -tm $nick *** Received old DH1024 public key from $nick $+ ...
    .notice $nick Received old DH1024 public key from you! Please update to latest Fish version: http://fish.sekure.us , http://mircryption.sourceforge.net
    var %tempkey $dll(%mc_sinnerscriptdll,DH1024_gen,NOT_USED)
    %mc_sinnerdh_prv_key = $gettok(%tempkey, 1, 32)
    %mc_sinnerdh_pub_key = $gettok(%tempkey, 2, 32)
    unset %tempkey

    var %secret = $dll(%mc_sinnerscriptdll,DH1024_comp, %mc_sinnerdh_prv_key $2)

    ; ATTN: set key for %nick to $secret (blow.setkey $nick %secret)

    %retv = $dll( %mc_scriptdll  , mc_setkey , $mcdh_cleanmultiserve($nick) %secret)
    if (%retv != $null) {
      ; echo 4 -s %retv
      echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange complete: %retv
      .notice $nick DH1024_FINISH %mc_sinnerdh_pub_key
    }
    else {
      echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange failed to set mircryption key.
      .notice $nick DH1024_FINISH ERROR
    }

    unset %mc_sinnerdh_dh $+ [ $mcdh_cleanmultiserve($nick) ]
    unset %mc_sinnerdh_prv_key
    unset %mc_sinnerdh_pub_key
    unset %secret
  }
  else {
    echo $color(Mode text) -tm $nick *** Improper DH1024 init from $nick, aborting exchange.
  }
  halt
}


on ^1:NOTICE:DH1024_FINISH*:?:{
  ; /echo @debug IN: DH1024_FINISH full string is $1-
  if ( %mc_sinnerdh_dh [ $+ [ $mcdh_cleanmultiserve($nick) ] ] != 1 ) {
    echo $color(Mode text) -tm $nick *** Received old DH1024 finalization from $nick but no keyXchange is in progress - noaction taken.
    halt
  }
  if ($len($2) <= 172 && $len($2) >= 170) {
    var %secret = $dll(%mc_sinnerscriptdll,DH1024_comp, %mc_sinnerdh_prv_key $2)

    ; ATTN: set key for %nick to $secret (blow.setkey $nick %secret)
    var %retv
    %retv = $dll( %mc_scriptdll  , mc_setkey , $mcdh_cleanmultiserve($nick) %secret)

    if (%retv != $null) {
      echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange complete: %retv
    }
    else {
      echo $color(Mode text) -tm $nick *** Mircryption Fish keyXchange failed to set mircryption key.
    }

    unset %mc_sinnerdh_dh $+ [ $mcdh_cleanmultiserve($nick) ]
    unset %mc_sinnerdh_prv_key
    unset %mc_sinnerdh_pub_key
    unset %secret
  }
  else {
    echo $color(Mode text) -tm $nick *** Improper DH1024 reply from $nick, aborting exchange.
  }
  halt
}
;---------------------------------------------------------------------------





;---------------------------------------------------------------------------
alias rndkey {
  var %cname = $1
  if (%cname == $null) %cname = $active
  %cname = $chatchan(%cname)
  var %tempkey $dll(%mc_sinnerscriptdll,DH1080_gen,NOT_USED)
  %mc_sinnerdh_prv_key = $gettok(%tempkey, 1, 32)
  %mc_sinnerdh_pub_key = $gettok(%tempkey, 2, 32)
  var %tempkey2 $dll(%mc_sinnerscriptdll,DH1080_gen,NOT_USED)
  %mc_sinnerdh_prv_key2 = $gettok(%tempkey2, 1, 32)
  %mc_sinnerdh_pub_key2 = $gettok(%tempkey2, 2, 32)
  var %secret = $dll(%mc_sinnerscriptdll,DH1080_comp, %mc_sinnerdh_prv_key2 %mc_sinnerdh_pub_key)
  setkey %cname cbc: $+ %secret
  /echo 4 %cname key for %cname randomized.
  return %secret
}
;---------------------------------------------------------------------------



;---------------------------------------------------------------------------
; just do a multiserv
alias mcdh_cleanmultiserve {
  return $cleanmultiserve($1)
}
;---------------------------------------------------------------------------

;---------------------------------------------------------------------------
;end of file



Feel free to use it - at your own risk, ofc! :)
Reviews welcome :)


Here is the original for a diff: https://www.donation.../MircryptionCore.zip