API login and MD5

Hi,

i can not login to routeros . i send >

<<< /login (send as length = 6 and “/login” as byte)
<<< (send 0 )

routeros answer

!done
=ret=9dda3fbe58072fed523fe5f6c4ce0644

i send
<<< /login
<<< =name=admin
<<< =response=00+md5New

md5New is >

string retOld = 9dda3fbe58072fed523fe5f6c4ce0644
string password = "1234"
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] md5Hash = md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes("00" + StringToHex(password) + RetOld));
string md5New = BitConverter.ToString(md5Hash);
md5New = md5New.Replace("-",""); // from 5A-6D-55 to 5A6D55 e.g. 
md5New = md5New.ToLower(); // from 5a6d55 e.g.

Mikrotik answer >

:club_suit:
!trap▬=message=cannot log in :club_suit:!done

pls help…

thx

it looks like basic and i do not know much about that, so i will give you example how i did it in java all what i need to login

mainly check login() method and other what i posted here is what i used in that login method

here is the thread:
http://forum.mikrotik.com/t/api-routerosv3/11568/40

so here it goes

this method is used to send last string of the command to the RouterOS, of course, it can be implemented some more elegant way, this is used to finish a command but:

    private void writeln(String s){
        try {
            out.writeByte( new Integer(s.length()).byteValue());
            out.writeBytes( s + "\0");
            System.out.println(s);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }


same as above, just sends one line of the command



    private void write(String s){
        try {
            Integer t = new Integer(s.length());
            out.writeByte(t.byteValue());
            out.writeBytes(s);
            System.out.println(s);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

this reads stuff that is returned by routeros API

    private String[] read(){
        String s="";
        boolean haveSymbols = true;
        try {
            char ch;
            while (true){
                while (haveSymbols){
                    byte b = in.readByte();
                    if (b!=0x00){
                        s+="\n";
                        
                        for (int count=0;count<b;count++){
                            ch = (char)(in.readByte() & 0xFF);
                            s+=ch;
                        }
                    }else haveSymbols=false;
                    
                }
                if (s.contains("!done")) return  s.split("\n");
                
                haveSymbols = true;
                
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return null;
    }

this is how to make connection using java

    public boolean connect(String ipAddress, int ipPort){
        boolean ret = false;
        try {
            socket = new Socket(ipAddress,ipPort);
            in = new DataInputStream(socket.getInputStream());
            out = new DataOutputStream(socket.getOutputStream());
            ret = true;
        } catch (UnknownHostException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return ret;
    }

this is how i managed the login

    
    public boolean login(String login, String password){
        String[] readIn;
        String transition ="";
        boolean ret = false;
        writeln("/login");
        readIn = read();
        for (int i=0; i<readIn.length;i++){
            System.out.println(readIn[i]);
        }
        String[] tmp = readIn[2].split("=ret=");
        transition = tmp[tmp.length-1];
        String chal="";
        chal=MessageDigestHelper.myHexStrToStr("00") + password + MessageDigestHelper.myHexStrToStr(transition);
        chal = MessageDigestHelper.myMD5Helper(chal);
        write("/login");
        write("=name="+login);
        writeln("=response=00"+chal);
        readIn = read();
        for (int i=0; i<readIn.length;i++){
            System.out.println(readIn[i]);
        }
        if (readIn[readIn.length-1].contains("!done")){
            if (readIn[1].contains("!trap")){
                return false;
            } else
                return true;
        }
        return ret;
    }

and now missing peaces that i used in login method (hope they are self explanatory:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 *
 * @author janisk
 */
public class MessageDigestHelper {
    
    /** Creates a new instance of MessageDigestHelper */
    public MessageDigestHelper() {
    }
    static public String myMD5Helper(String s){
        String md5val = "";
        MessageDigest algorithm = null;
        try {
            algorithm = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException nsae) {
            System.out.println("Cannot find digest algorithm");
            System.exit(1);
        }
        byte[] defaultBytes = new byte[s.length()];
        for (int i=0;i<s.length();i++){
            defaultBytes[i] = (byte)(0xFF & s.charAt(i));
        }
        algorithm.reset();
        algorithm.update(defaultBytes);
        byte messageDigest[] = algorithm.digest();
        StringBuffer hexString = new StringBuffer();
        
        for (int i = 0; i < messageDigest.length; i++) {
            String hex = Integer.toHexString(0xFF & messageDigest[i]);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
    static public String myHexStrToStr(String s){
        String ret ="";
        for (int i = 0; i<s.length();i+=2){
            ret += (char)Integer.parseInt(s.substring(i,i+2),16);
        }
        return ret;
    }
}

one missing method

it is used to send commands and receive the results

    public String[] progTalk(String text){
        text=text.trim();
        int counter = 0;
        String tag = "";
        if (text.contains("\n")){
            tag = text.substring(0,text.indexOf("\n"));
        } else tag = text;
        text = text.concat("\n.tag="+tag);
        String[] internalText = text.split("\n");
        while (counter < internalText.length-1){
            write(internalText[counter]);
            counter++;
        }
        writeln(internalText[counter]);
        return read();
    }

hope it helps as java is not that different from C#

thx thx thx

i try it and post results

MikroTik, why do you use md5(“\0” + paswd + challenge)? it’s easy to bruteforce password, if you know the challenge and the answer! maybe look at HMAC algorithm or others?

Is it possible to save scan data received form the router when I send via a java API:
/interface/wireless/scan
=.id=X
?

it does not matter much what programming language you use to use API calls on RouterOS.

to get scan you use command:

/interface/wireless/scan
=.id=*4

i would suggest to use TAG, so you can /cancel the command and not every other single command that is running at the moment.

also your =tag= will be used to report back, so you can see the difference from what command you are receiving data.

I have two wlan interfaces and if I try either “=.id=*0” or “=.id=*1” it gives me this output:

!trap=message=no such item (4)
!done

… Do you know where could be a problem?

You need to retrieve the item numbers for the wireless cards. If you are just testing, you can find the id of the cards with this at the command prompt:

/interface wireless
:put [find];

The values displayed should explain themselves.

BTW, you should have started an new topic.

I tried it and here is the result:

[admin@Mikrotik] /interface wireless> :put [find]
*b;*c

… maybe its too late for the values to explain themselves :wink: but I don’t get what that *b and *c means. I tried to use it as an .id, but did not work again.

Could you please explain me.

PS:Thanks for warning, next time I ll start a new topic.

I have only one card in my test unit, and it returns *4.
If I do the same in “/interface ethernet”, it returns *1;*2;*3
Got me…

by the way, you may use ‘name’ value in ‘.id’ field: ‘=.id=wlan1,wlan2,*ab12’

Hi!, i have compiled the classes, i see the log in the mikrotik, and i can login, but i don’t understand how to retrieve data.
I have routeros 4.5, and i test the classes as follows:
public static void main(String args){
mkt m=new mtk();
m.connect(“189…”,8728);
m.login(“admin”,“password”);
}

Thanks and sorry for my english.

it depends on your implementation

it should be noted that .ID fields are in hexadecimal system, seeing *5,*b,*c,*10 in decimal would look like *5,*11,*12,*16

data retrieval works similar to CLI, just with small changes
look here for details:
http://wiki.mikrotik.com/wiki/API

and links.

if you are logged in, that means you can read from socket and write to it, you are like 99% done :slight_smile:

now, just make that you can send other commands and read from socket. you can look at login method to see how reading and writing is done.

Hello there,
I really appreciate this example and the example in wiki. But I have little problem with retrieving data from DataInputStream. Basically, when I’m requesting a large amount of data and the Mikrotik device is busy, the DataInputStream (or Socket) doesn’t retrieves any data and uses NULL instead. It uses NULL simply because it has no data.

In fact, if the word (row) has length of 100 bytes, we retrive only first 70 bytes, then is delay (made by Mikrotik device), this delay is replaced with NULL by Socker reader. And missing 30 bytes are mixed in the next word (row). The final output looks like this:
=.id=*16
=address=10.20.7.35
=mac-ad
ress=00:00:DB:22:1A:2E=client-id=1:0:0:db:22:1a:2e
=server=dhcp1
=radius=false=dynamic=false=bloc
ed=false=disabled=true]=comment=Piha

We found temporary solution with ugly hack in ReadCommand class:
a = in.read(bb, 0, sk);
Thread.sleep(20);

But haven’t anybody experienced this issue too? I don’t like our solution and I willl be very grateful for better suggestion.

Thank you.

i wanna add new account on userman (with some options : Profile,User,Pass,Email…) . how can do it with command ? (in C#.net4 - WinApp)

if i have understood you correctly you have to take updated java API that has correct read/write function. It seems that you encounter.

It can read length of up to 0x80 bytes. As result you read only part and then output gets bad. and get a lot of NULLs as result, since buffer you are reading from is empty.